solargraph 0.55.4 → 0.55.5
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/.github/workflows/plugins.yml +2 -0
- data/.github/workflows/typecheck.yml +2 -0
- data/.gitignore +2 -0
- data/CHANGELOG.md +3 -0
- data/README.md +13 -3
- data/lib/solargraph/api_map/index.rb +23 -15
- data/lib/solargraph/api_map/store.rb +2 -1
- data/lib/solargraph/api_map.rb +53 -27
- data/lib/solargraph/complex_type/type_methods.rb +5 -1
- data/lib/solargraph/complex_type/unique_type.rb +7 -0
- data/lib/solargraph/convention/base.rb +3 -3
- data/lib/solargraph/convention.rb +3 -3
- data/lib/solargraph/doc_map.rb +189 -43
- data/lib/solargraph/gem_pins.rb +53 -38
- data/lib/solargraph/language_server/host.rb +9 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -0
- data/lib/solargraph/language_server/message/extended/document.rb +5 -2
- data/lib/solargraph/language_server/message/extended/document_gems.rb +3 -3
- data/lib/solargraph/library.rb +7 -4
- data/lib/solargraph/location.rb +13 -0
- data/lib/solargraph/parser/parser_gem/class_methods.rb +5 -8
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +2 -2
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +2 -2
- data/lib/solargraph/pin/base.rb +268 -24
- data/lib/solargraph/pin/base_variable.rb +9 -8
- data/lib/solargraph/pin/callable.rb +69 -0
- data/lib/solargraph/pin/closure.rb +12 -0
- data/lib/solargraph/pin/local_variable.rb +8 -5
- data/lib/solargraph/pin/method.rb +134 -17
- data/lib/solargraph/pin/parameter.rb +43 -6
- data/lib/solargraph/pin/signature.rb +38 -0
- data/lib/solargraph/pin_cache.rb +185 -0
- data/lib/solargraph/position.rb +9 -0
- data/lib/solargraph/range.rb +9 -0
- data/lib/solargraph/rbs_map/conversions.rb +19 -8
- data/lib/solargraph/rbs_map/core_map.rb +31 -9
- data/lib/solargraph/rbs_map/stdlib_map.rb +15 -5
- data/lib/solargraph/rbs_map.rb +74 -17
- data/lib/solargraph/shell.rb +11 -15
- data/lib/solargraph/source_map.rb +0 -17
- data/lib/solargraph/version.rb +1 -1
- data/lib/solargraph/views/_method.erb +10 -10
- data/lib/solargraph/views/_namespace.erb +3 -3
- data/lib/solargraph/views/document.erb +10 -10
- data/lib/solargraph/workspace.rb +15 -5
- data/lib/solargraph/yardoc.rb +3 -11
- data/lib/solargraph.rb +10 -12
- data/rbs_collection.yaml +19 -0
- data/solargraph.gemspec +1 -0
- metadata +19 -7
- data/lib/solargraph/cache.rb +0 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e015963ad868b3671d88892483ec3c06a3e7c96757f2013ba56c514af35eb0e
|
4
|
+
data.tar.gz: 22a6383d6f179ec708a930fbf8cb81bea8cbbee694de559f43208c859240a0cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd7b151efc8a584829cdc5c4424c81dd3703dd22f8287c8edfcfc32d65b8409e8be9d8354ed5369c6fa0955cc1ccd534014f6782aa71ca7b0a89c5df8a0d9b06
|
7
|
+
data.tar.gz: 818390cee111c7948e40904e1eb48dd407dd8f15045a29b96881e6bb520022438d9fca6a7ec678dbc6d793f74b3bcdaf17d4b152e86bb5b1f563f1703423a7ed
|
@@ -34,6 +34,8 @@ jobs:
|
|
34
34
|
bundle exec solargraph config
|
35
35
|
yq -yi '.plugins += ["solargraph-rails"]' .solargraph.yml
|
36
36
|
yq -yi '.plugins += ["solargraph-rspec"]' .solargraph.yml
|
37
|
+
- name: Install gem types
|
38
|
+
run: bundle exec rbs collection install
|
37
39
|
- name: Ensure typechecking still works
|
38
40
|
run: bundle exec solargraph typecheck --level typed
|
39
41
|
- name: Ensure specs still run
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -63,12 +63,22 @@ The RSpec framework is supported via [solargraph-rspec](https://github.com/lekem
|
|
63
63
|
|
64
64
|
**Note: Before version 0.53.0, it was recommended to run `yard gems` periodically or automate it with `yard config` to ensure that Solargraph had access to gem documentation. These steps are no longer necessary. Solargraph maintains its own gem documentation cache independent of the yardocs in your gem installations.**
|
65
65
|
|
66
|
-
Solargraph automatically generates code maps from installed gems.
|
67
|
-
|
68
|
-
When editing code, a `require` call that references a gem will pull the documentation into the code maps and include the gem's API in code completion and intellisense.
|
66
|
+
When editing code, a `require` call that references a gem will pull the documentation into the code maps and include the gem's API in code completion and intellisense. Solargraph automatically generates code maps from installed gems, based on the YARD or RBS type information inside the gem. You can also eagerly cache gem documentation with the `solargraph gems` command.
|
69
67
|
|
70
68
|
If your project automatically requires bundled gems (e.g., `require 'bundler/require'`), Solargraph will add all of the Gemfile's default dependencies to the map.
|
71
69
|
|
70
|
+
To ensure you have types for gems which contain neither RBS nor YARD
|
71
|
+
information, use
|
72
|
+
[gem\_rbs\_collection](https://github.com/ruby/gem_rbs_collection) to
|
73
|
+
install a community-supported set of RBS types for various gems:
|
74
|
+
|
75
|
+
```sh
|
76
|
+
bundle exec rbs collection init
|
77
|
+
bundle exec rbs collection install
|
78
|
+
```
|
79
|
+
|
80
|
+
Once installed, you can also insert your own local overrides and definitions in RBS in a directory configured in the `rbs_collection.yaml` that the above commands create.
|
81
|
+
|
72
82
|
### Type Checking
|
73
83
|
|
74
84
|
As of version 0.33.0, Solargraph includes a [type checker](https://github.com/castwide/solargraph/issues/192) that uses a combination of YARD tags and code analysis to report missing type definitions. In strict mode, it performs type inference to determine whether the tags match the types it detects from code.
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module Solargraph
|
4
4
|
class ApiMap
|
5
5
|
class Index
|
6
|
+
include Logging
|
7
|
+
|
6
8
|
# @param pins [Array<Pin::Base>]
|
7
9
|
def initialize pins = []
|
8
10
|
catalog pins
|
@@ -132,21 +134,24 @@ module Solargraph
|
|
132
134
|
# @return [void]
|
133
135
|
def map_overrides
|
134
136
|
pins_by_class(Pin::Reference::Override).each do |ovr|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
137
|
+
logger.debug { "ApiMap::Index#map_overrides: Looking at override #{ovr} for #{ovr.name}" }
|
138
|
+
pins = path_pin_hash[ovr.name]
|
139
|
+
logger.debug { "ApiMap::Index#map_overrides: pins for path=#{ovr.name}: #{pins}" }
|
140
|
+
pins.each do |pin|
|
141
|
+
new_pin = if pin.path.end_with?('#initialize')
|
142
|
+
path_pin_hash[pin.path.sub(/#initialize/, '.new')].first
|
143
|
+
end
|
144
|
+
(ovr.tags.map(&:tag_name) + ovr.delete).uniq.each do |tag|
|
145
|
+
pin.docstring.delete_tags tag
|
146
|
+
new_pin.docstring.delete_tags tag if new_pin
|
147
|
+
end
|
148
|
+
ovr.tags.each do |tag|
|
149
|
+
pin.docstring.add_tag(tag)
|
150
|
+
redefine_return_type pin, tag
|
151
|
+
if new_pin
|
152
|
+
new_pin.docstring.add_tag(tag)
|
153
|
+
redefine_return_type new_pin, tag
|
154
|
+
end
|
150
155
|
end
|
151
156
|
end
|
152
157
|
end
|
@@ -156,11 +161,14 @@ module Solargraph
|
|
156
161
|
# @param tag [YARD::Tags::Tag]
|
157
162
|
# @return [void]
|
158
163
|
def redefine_return_type pin, tag
|
164
|
+
# @todo can this be made to not mutate existing pins and use
|
165
|
+
# proxy() / proxy_with_signatures() instead?
|
159
166
|
return unless pin && tag.tag_name == 'return'
|
160
167
|
pin.instance_variable_set(:@return_type, ComplexType.try_parse(tag.type))
|
161
168
|
pin.signatures.each do |sig|
|
162
169
|
sig.instance_variable_set(:@return_type, ComplexType.try_parse(tag.type))
|
163
170
|
end
|
171
|
+
pin.reset_generated!
|
164
172
|
end
|
165
173
|
end
|
166
174
|
end
|
@@ -61,9 +61,10 @@ module Solargraph
|
|
61
61
|
# @param visibility [Array<Symbol>]
|
62
62
|
# @return [Enumerable<Solargraph::Pin::Method>]
|
63
63
|
def get_methods fqns, scope: :instance, visibility: [:public]
|
64
|
-
namespace_children(fqns).select do |pin|
|
64
|
+
all_pins = namespace_children(fqns).select do |pin|
|
65
65
|
pin.is_a?(Pin::Method) && pin.scope == scope && visibility.include?(pin.visibility)
|
66
66
|
end
|
67
|
+
GemPins.combine_method_pins_by_path(all_pins)
|
67
68
|
end
|
68
69
|
|
69
70
|
# @param fq_tag [String]
|
data/lib/solargraph/api_map.rb
CHANGED
@@ -93,9 +93,13 @@ module Solargraph
|
|
93
93
|
implicit.merge map.environ
|
94
94
|
end
|
95
95
|
unresolved_requires = (bench.external_requires + implicit.requires + bench.workspace.config.required).to_a.compact.uniq
|
96
|
-
|
96
|
+
recreate_docmap = @unresolved_requires != unresolved_requires ||
|
97
|
+
@doc_map&.uncached_yard_gemspecs&.any? ||
|
98
|
+
@doc_map&.uncached_rbs_collection_gemspecs&.any? ||
|
99
|
+
@doc_map&.rbs_collection_path != bench.workspace.rbs_collection_path
|
100
|
+
if recreate_docmap
|
97
101
|
@doc_map = DocMap.new(unresolved_requires, [], bench.workspace) # @todo Implement gem preferences
|
98
|
-
@unresolved_requires = unresolved_requires
|
102
|
+
@unresolved_requires = @doc_map.unresolved_requires
|
99
103
|
end
|
100
104
|
@cache.clear if store.update(@@core_map.pins, @doc_map.pins, implicit.pins, iced_pins, live_pins)
|
101
105
|
@missing_docs = [] # @todo Implement missing docs
|
@@ -109,11 +113,25 @@ module Solargraph
|
|
109
113
|
[self.class, @source_map_hash, implicit, @doc_map, @unresolved_requires]
|
110
114
|
end
|
111
115
|
|
116
|
+
def doc_map
|
117
|
+
@doc_map ||= DocMap.new([], [])
|
118
|
+
end
|
119
|
+
|
112
120
|
# @return [::Array<Gem::Specification>]
|
113
121
|
def uncached_gemspecs
|
114
122
|
@doc_map&.uncached_gemspecs || []
|
115
123
|
end
|
116
124
|
|
125
|
+
# @return [::Array<Gem::Specification>]
|
126
|
+
def uncached_rbs_collection_gemspecs
|
127
|
+
@doc_map.uncached_rbs_collection_gemspecs
|
128
|
+
end
|
129
|
+
|
130
|
+
# @return [::Array<Gem::Specification>]
|
131
|
+
def uncached_yard_gemspecs
|
132
|
+
@doc_map.uncached_yard_gemspecs
|
133
|
+
end
|
134
|
+
|
117
135
|
# @return [Array<Pin::Base>]
|
118
136
|
def core_pins
|
119
137
|
@@core_map.pins
|
@@ -168,6 +186,18 @@ module Solargraph
|
|
168
186
|
api_map
|
169
187
|
end
|
170
188
|
|
189
|
+
def cache_all!(out)
|
190
|
+
@doc_map.cache_all!(out)
|
191
|
+
end
|
192
|
+
|
193
|
+
def cache_gem(gemspec, rebuild: false, out: nil)
|
194
|
+
@doc_map.cache(gemspec, rebuild: rebuild, out: out)
|
195
|
+
end
|
196
|
+
|
197
|
+
class << self
|
198
|
+
include Logging
|
199
|
+
end
|
200
|
+
|
171
201
|
# Create an ApiMap with a workspace in the specified directory and cache
|
172
202
|
# any missing gems.
|
173
203
|
#
|
@@ -178,15 +208,14 @@ module Solargraph
|
|
178
208
|
# @param directory [String]
|
179
209
|
# @param out [IO] The output stream for messages
|
180
210
|
# @return [ApiMap]
|
181
|
-
def self.load_with_cache directory, out
|
211
|
+
def self.load_with_cache directory, out
|
182
212
|
api_map = load(directory)
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
out.puts "Caching gem #{gemspec.name} #{gemspec.version}"
|
187
|
-
pins = GemPins.build(gemspec)
|
188
|
-
Solargraph::Cache.save('gems', "#{gemspec.name}-#{gemspec.version}.ser", pins)
|
213
|
+
if api_map.uncached_gemspecs.empty?
|
214
|
+
logger.info { "All gems cached for #{directory}" }
|
215
|
+
return api_map
|
189
216
|
end
|
217
|
+
|
218
|
+
api_map.cache_all!(out)
|
190
219
|
load(directory)
|
191
220
|
end
|
192
221
|
|
@@ -527,13 +556,8 @@ module Solargraph
|
|
527
556
|
.select { |path| path.downcase.include?(query.downcase) }
|
528
557
|
end
|
529
558
|
|
530
|
-
#
|
531
|
-
#
|
532
|
-
# @example
|
533
|
-
# api_map.document('String#split')
|
534
|
-
#
|
535
|
-
# @todo This method is likely superfluous. Calling get_path_pins directly
|
536
|
-
# should be sufficient.
|
559
|
+
# @deprecated This method is likely superfluous. Calling #get_path_pins
|
560
|
+
# directly should be sufficient.
|
537
561
|
#
|
538
562
|
# @param path [String] The path to find
|
539
563
|
# @return [Enumerable<Pin::Base>]
|
@@ -627,6 +651,19 @@ module Solargraph
|
|
627
651
|
store.get_includes(host_ns).map { |inc_tag| ComplexType.parse(inc_tag).name }.include?(module_ns)
|
628
652
|
end
|
629
653
|
|
654
|
+
# @param pins [Enumerable<Pin::Base>]
|
655
|
+
# @param visibility [Enumerable<Symbol>]
|
656
|
+
# @return [Array<Pin::Base>]
|
657
|
+
def resolve_method_aliases pins, visibility = [:public, :private, :protected]
|
658
|
+
with_resolved_aliases = pins.map do |pin|
|
659
|
+
resolved = resolve_method_alias(pin)
|
660
|
+
next nil if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
|
661
|
+
resolved
|
662
|
+
end.compact
|
663
|
+
logger.debug { "ApiMap#resolve_method_aliases(pins=#{pins.map(&:name)}, visibility=#{visibility}) => #{with_resolved_aliases.map(&:name)}" }
|
664
|
+
GemPins.combine_method_pins_by_path(with_resolved_aliases)
|
665
|
+
end
|
666
|
+
|
630
667
|
private
|
631
668
|
|
632
669
|
# A hash of source maps with filename keys.
|
@@ -859,17 +896,6 @@ module Solargraph
|
|
859
896
|
result + nil_pins
|
860
897
|
end
|
861
898
|
|
862
|
-
# @param pins [Enumerable<Pin::Base>]
|
863
|
-
# @param visibility [Enumerable<Symbol>]
|
864
|
-
# @return [Array<Pin::Base>]
|
865
|
-
def resolve_method_aliases pins, visibility = [:public, :private, :protected]
|
866
|
-
pins.map do |pin|
|
867
|
-
resolved = resolve_method_alias(pin)
|
868
|
-
next pin if resolved.respond_to?(:visibility) && !visibility.include?(resolved.visibility)
|
869
|
-
resolved
|
870
|
-
end.compact
|
871
|
-
end
|
872
|
-
|
873
899
|
# @param pin [Pin::MethodAlias, Pin::Base]
|
874
900
|
# @return [Pin::Method]
|
875
901
|
def resolve_method_alias pin
|
@@ -172,7 +172,11 @@ module Solargraph
|
|
172
172
|
elsif fixed_parameters?
|
173
173
|
"(#{subtypes_str})"
|
174
174
|
else
|
175
|
-
|
175
|
+
if name == 'Hash'
|
176
|
+
"<#{key_types_str}, #{subtypes_str}>"
|
177
|
+
else
|
178
|
+
"<#{key_types_str}#{subtypes_str}>"
|
179
|
+
end
|
176
180
|
end
|
177
181
|
end
|
178
182
|
|
@@ -55,6 +55,13 @@ module Solargraph
|
|
55
55
|
key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
|
56
56
|
# @sg-ignore
|
57
57
|
subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
|
58
|
+
elsif parameters_type == :list && name == 'Hash'
|
59
|
+
# Treat Hash<A, B> as Hash{A => B}
|
60
|
+
if subs.length != 2
|
61
|
+
raise ComplexTypeError, "Bad hash type: name=#{name}, substring=#{substring} - must have exactly two parameters"
|
62
|
+
end
|
63
|
+
key_types.concat(subs[0].map { |u| ComplexType.new([u]) })
|
64
|
+
subtypes.concat(subs[1].map { |u| ComplexType.new([u]) })
|
58
65
|
else
|
59
66
|
subtypes.concat subs
|
60
67
|
end
|
@@ -20,12 +20,12 @@ module Solargraph
|
|
20
20
|
EMPTY_ENVIRON
|
21
21
|
end
|
22
22
|
|
23
|
-
# The Environ for a
|
23
|
+
# The Environ for a DocMap.
|
24
24
|
# Subclasses can override this method.
|
25
25
|
#
|
26
|
-
# @param
|
26
|
+
# @param doc_map [DocMap]
|
27
27
|
# @return [Environ]
|
28
|
-
def global
|
28
|
+
def global doc_map
|
29
29
|
EMPTY_ENVIRON
|
30
30
|
end
|
31
31
|
end
|
@@ -31,12 +31,12 @@ module Solargraph
|
|
31
31
|
result
|
32
32
|
end
|
33
33
|
|
34
|
-
# @param yard_map [
|
34
|
+
# @param yard_map [DocMap]
|
35
35
|
# @return [Environ]
|
36
|
-
def self.for_global(
|
36
|
+
def self.for_global(doc_map)
|
37
37
|
result = Environ.new
|
38
38
|
@@conventions.each do |conv|
|
39
|
-
result.merge conv.global(
|
39
|
+
result.merge conv.global(doc_map)
|
40
40
|
end
|
41
41
|
result
|
42
42
|
end
|
data/lib/solargraph/doc_map.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'pathname'
|
4
|
+
require 'benchmark'
|
5
|
+
|
3
6
|
module Solargraph
|
4
7
|
# A collection of pins generated from required gems.
|
5
8
|
#
|
@@ -8,6 +11,7 @@ module Solargraph
|
|
8
11
|
|
9
12
|
# @return [Array<String>]
|
10
13
|
attr_reader :requires
|
14
|
+
alias required requires
|
11
15
|
|
12
16
|
# @return [Array<Gem::Specification>]
|
13
17
|
attr_reader :preferences
|
@@ -16,11 +20,27 @@ module Solargraph
|
|
16
20
|
attr_reader :pins
|
17
21
|
|
18
22
|
# @return [Array<Gem::Specification>]
|
19
|
-
|
23
|
+
def uncached_gemspecs
|
24
|
+
(uncached_yard_gemspecs + uncached_rbs_collection_gemspecs).sort.
|
25
|
+
uniq { |gemspec| "#{gemspec.name}:#{gemspec.version}" }
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Array<Gem::Specification>]
|
29
|
+
attr_reader :uncached_yard_gemspecs
|
30
|
+
|
31
|
+
# @return [Array<Gem::Specification>]
|
32
|
+
attr_reader :uncached_rbs_collection_gemspecs
|
33
|
+
|
34
|
+
attr_reader :rbs_collection_path
|
35
|
+
|
36
|
+
attr_reader :rbs_collection_config_path
|
20
37
|
|
21
38
|
# @return [Workspace, nil]
|
22
39
|
attr_reader :workspace
|
23
40
|
|
41
|
+
# @return [Environ]
|
42
|
+
attr_reader :environ
|
43
|
+
|
24
44
|
# @param requires [Array<String>]
|
25
45
|
# @param preferences [Array<Gem::Specification>]
|
26
46
|
# @param workspace [Workspace, nil]
|
@@ -28,7 +48,51 @@ module Solargraph
|
|
28
48
|
@requires = requires.compact
|
29
49
|
@preferences = preferences.compact
|
30
50
|
@workspace = workspace
|
31
|
-
|
51
|
+
@rbs_collection_path = workspace&.rbs_collection_path
|
52
|
+
@rbs_collection_config_path = workspace&.rbs_collection_config_path
|
53
|
+
@environ = Convention.for_global(self)
|
54
|
+
load_serialized_gem_pins
|
55
|
+
pins.concat @environ.pins
|
56
|
+
end
|
57
|
+
|
58
|
+
def cache_all!(out)
|
59
|
+
# if we log at debug level:
|
60
|
+
if logger.info?
|
61
|
+
gem_desc = uncached_gemspecs.map { |gemspec| "#{gemspec.name}:#{gemspec.version}" }.join(', ')
|
62
|
+
logger.info "Caching pins for gems: #{gem_desc}" unless uncached_gemspecs.empty?
|
63
|
+
end
|
64
|
+
logger.debug { "Caching for YARD: #{uncached_yard_gemspecs.map(&:name)}" }
|
65
|
+
logger.debug { "Caching for RBS collection: #{uncached_rbs_collection_gemspecs.map(&:name)}" }
|
66
|
+
load_serialized_gem_pins
|
67
|
+
uncached_gemspecs.each do |gemspec|
|
68
|
+
cache(gemspec, out: out)
|
69
|
+
end
|
70
|
+
load_serialized_gem_pins
|
71
|
+
@uncached_rbs_collection_gemspecs = []
|
72
|
+
@uncached_yard_gemspecs = []
|
73
|
+
end
|
74
|
+
|
75
|
+
def cache_yard_pins(gemspec, out)
|
76
|
+
pins = GemPins.build_yard_pins(gemspec)
|
77
|
+
PinCache.serialize_yard_gem(gemspec, pins)
|
78
|
+
logger.info { "Cached #{pins.length} YARD pins for gem #{gemspec.name}:#{gemspec.version}" } unless pins.empty?
|
79
|
+
end
|
80
|
+
|
81
|
+
def cache_rbs_collection_pins(gemspec, out)
|
82
|
+
rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
|
83
|
+
pins = rbs_map.pins
|
84
|
+
rbs_version_cache_key = rbs_map.cache_key
|
85
|
+
# cache pins even if result is zero, so we don't retry building pins
|
86
|
+
pins ||= []
|
87
|
+
PinCache.serialize_rbs_collection_gem(gemspec, rbs_version_cache_key, pins)
|
88
|
+
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? }
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param gemspec [Gem::Specification]
|
92
|
+
def cache(gemspec, rebuild: false, out: nil)
|
93
|
+
out.puts("Caching pins for gem #{gemspec.name}:#{gemspec.version}") if out
|
94
|
+
cache_yard_pins(gemspec, out) if uncached_yard_gemspecs.include?(gemspec) || rebuild
|
95
|
+
cache_rbs_collection_pins(gemspec, out) if uncached_rbs_collection_gemspecs.include?(gemspec) || rebuild
|
32
96
|
end
|
33
97
|
|
34
98
|
# @return [Array<Gem::Specification>]
|
@@ -41,9 +105,24 @@ module Solargraph
|
|
41
105
|
@unresolved_requires ||= required_gems_map.select { |_, gemspecs| gemspecs.nil? }.keys
|
42
106
|
end
|
43
107
|
|
44
|
-
|
45
|
-
|
46
|
-
|
108
|
+
def self.all_yard_gems_in_memory
|
109
|
+
@yard_gems_in_memory ||= {}
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.all_rbs_collection_gems_in_memory
|
113
|
+
@rbs_collection_gems_in_memory ||= {}
|
114
|
+
end
|
115
|
+
|
116
|
+
def yard_pins_in_memory
|
117
|
+
self.class.all_yard_gems_in_memory
|
118
|
+
end
|
119
|
+
|
120
|
+
def rbs_collection_pins_in_memory
|
121
|
+
self.class.all_rbs_collection_gems_in_memory[rbs_collection_path] ||= {}
|
122
|
+
end
|
123
|
+
|
124
|
+
def combined_pins_in_memory
|
125
|
+
@combined_pins_in_memory ||= {}
|
47
126
|
end
|
48
127
|
|
49
128
|
# @return [Set<Gem::Specification>]
|
@@ -54,20 +133,29 @@ module Solargraph
|
|
54
133
|
private
|
55
134
|
|
56
135
|
# @return [void]
|
57
|
-
def
|
136
|
+
def load_serialized_gem_pins
|
58
137
|
@pins = []
|
59
|
-
@
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
138
|
+
@uncached_yard_gemspecs = []
|
139
|
+
@uncached_rbs_collection_gemspecs = []
|
140
|
+
with_gemspecs, without_gemspecs = required_gems_map.partition { |_, v| v }
|
141
|
+
paths = Hash[without_gemspecs].keys
|
142
|
+
gemspecs = Hash[with_gemspecs].values.flatten.compact + dependencies.to_a
|
143
|
+
|
144
|
+
paths.each do |path|
|
145
|
+
rbs_pins = deserialize_stdlib_rbs_map path
|
146
|
+
end
|
147
|
+
|
148
|
+
logger.debug { "DocMap#load_serialized_gem_pins: Combining pins..." }
|
149
|
+
time = Benchmark.measure do
|
150
|
+
gemspecs.each do |gemspec|
|
151
|
+
pins = deserialize_combined_pin_cache gemspec
|
152
|
+
@pins.concat pins if pins
|
67
153
|
end
|
68
154
|
end
|
69
|
-
|
70
|
-
@
|
155
|
+
logger.info { "DocMap#load_serialized_gem_pins: Loaded and processed serialized pins together in #{time.real} seconds" }
|
156
|
+
@uncached_yard_gemspecs.uniq!
|
157
|
+
@uncached_rbs_collection_gemspecs.uniq!
|
158
|
+
nil
|
71
159
|
end
|
72
160
|
|
73
161
|
# @return [Hash{String => Array<Gem::Specification>}]
|
@@ -80,32 +168,97 @@ module Solargraph
|
|
80
168
|
@preference_map ||= preferences.to_h { |gemspec| [gemspec.name, gemspec] }
|
81
169
|
end
|
82
170
|
|
171
|
+
# @param gemspec [Gem::Specification]
|
172
|
+
# @return [Array<Pin::Base>]
|
173
|
+
def deserialize_yard_pin_cache gemspec
|
174
|
+
if yard_pins_in_memory.key?([gemspec.name, gemspec.version])
|
175
|
+
return yard_pins_in_memory[[gemspec.name, gemspec.version]]
|
176
|
+
end
|
177
|
+
|
178
|
+
cached = PinCache.deserialize_yard_gem(gemspec)
|
179
|
+
if cached
|
180
|
+
logger.info { "Loaded #{cached.length} cached YARD pins from #{gemspec.name}:#{gemspec.version}" }
|
181
|
+
yard_pins_in_memory[[gemspec.name, gemspec.version]] = cached
|
182
|
+
cached
|
183
|
+
else
|
184
|
+
logger.debug "No YARD pin cache for #{gemspec.name}:#{gemspec.version}"
|
185
|
+
@uncached_yard_gemspecs.push gemspec
|
186
|
+
nil
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
83
190
|
# @param gemspec [Gem::Specification]
|
84
191
|
# @return [void]
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
192
|
+
def deserialize_combined_pin_cache(gemspec)
|
193
|
+
unless combined_pins_in_memory[[gemspec.name, gemspec.version]].nil?
|
194
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
195
|
+
end
|
196
|
+
|
197
|
+
rbs_map = RbsMap.from_gemspec(gemspec, rbs_collection_path, rbs_collection_config_path)
|
198
|
+
rbs_version_cache_key = rbs_map.cache_key
|
199
|
+
|
200
|
+
cached = PinCache.deserialize_combined_gem(gemspec, rbs_version_cache_key)
|
201
|
+
if cached
|
202
|
+
logger.info { "Loaded #{cached.length} cached YARD pins from #{gemspec.name}:#{gemspec.version}" }
|
203
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = cached
|
204
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
205
|
+
end
|
206
|
+
|
207
|
+
rbs_collection_pins = deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
208
|
+
|
209
|
+
yard_pins = deserialize_yard_pin_cache gemspec
|
210
|
+
|
211
|
+
if !rbs_collection_pins.nil? && !yard_pins.nil?
|
212
|
+
logger.debug { "Combining pins for #{gemspec.name}:#{gemspec.version}" }
|
213
|
+
combined_pins = GemPins.combine(yard_pins, rbs_collection_pins)
|
214
|
+
PinCache.serialize_combined_gem(gemspec, rbs_version_cache_key, combined_pins)
|
215
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = combined_pins
|
216
|
+
logger.info { "Generated #{combined_pins_in_memory[[gemspec.name, gemspec.version]].length} combined pins for #{gemspec.name} #{gemspec.version}" }
|
217
|
+
return combined_pins
|
218
|
+
end
|
219
|
+
|
220
|
+
if !yard_pins.nil?
|
221
|
+
logger.debug { "Using only YARD pins for #{gemspec.name}:#{gemspec.version}" }
|
222
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = yard_pins
|
223
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
224
|
+
elsif !rbs_collection_pins.nil?
|
225
|
+
logger.debug { "Using only RBS collection pins for #{gemspec.name}:#{gemspec.version}" }
|
226
|
+
combined_pins_in_memory[[gemspec.name, gemspec.version]] = rbs_collection_pins
|
227
|
+
return combined_pins_in_memory[[gemspec.name, gemspec.version]]
|
93
228
|
else
|
94
|
-
|
95
|
-
|
229
|
+
logger.debug { "Pins not yet cached for #{gemspec.name}:#{gemspec.version}" }
|
230
|
+
return nil
|
96
231
|
end
|
97
232
|
end
|
98
233
|
|
99
234
|
# @param path [String] require path that might be in the RBS stdlib collection
|
100
235
|
# @return [void]
|
101
|
-
def
|
236
|
+
def deserialize_stdlib_rbs_map path
|
102
237
|
map = RbsMap::StdlibMap.load(path)
|
103
238
|
if map.resolved?
|
104
|
-
|
239
|
+
logger.debug { "Loading stdlib pins for #{path}" }
|
105
240
|
@pins.concat map.pins
|
241
|
+
logger.debug { "Loaded #{map.pins.length} stdlib pins for #{path}" }
|
242
|
+
map.pins
|
106
243
|
else
|
107
244
|
# @todo Temporarily ignoring unresolved `require 'set'`
|
108
|
-
|
245
|
+
logger.debug { "Require path #{path} could not be resolved in RBS" } unless path == 'set'
|
246
|
+
nil
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
# @return [Array<Pin::Base>, nil]
|
251
|
+
def deserialize_rbs_collection_cache gemspec, rbs_version_cache_key
|
252
|
+
return if rbs_collection_pins_in_memory.key?([gemspec, rbs_version_cache_key])
|
253
|
+
cached = PinCache.deserialize_rbs_collection_gem(gemspec, rbs_version_cache_key)
|
254
|
+
if cached
|
255
|
+
logger.info { "Loaded #{cached.length} pins from RBS collection cache for #{gemspec.name}:#{gemspec.version}" } unless cached.empty?
|
256
|
+
rbs_collection_pins_in_memory[[gemspec, rbs_version_cache_key]] = cached
|
257
|
+
cached
|
258
|
+
else
|
259
|
+
logger.debug "No RBS collection pin cache for #{gemspec.name} #{gemspec.version}"
|
260
|
+
@uncached_rbs_collection_gemspecs.push gemspec
|
261
|
+
nil
|
109
262
|
end
|
110
263
|
end
|
111
264
|
|
@@ -119,18 +272,6 @@ module Solargraph
|
|
119
272
|
true
|
120
273
|
end
|
121
274
|
|
122
|
-
# @param gemspec [Gem::Specification]
|
123
|
-
def update_from_collection gemspec, gempins
|
124
|
-
return gempins unless workspace&.rbs_collection_path && File.directory?(workspace&.rbs_collection_path)
|
125
|
-
return gempins if RbsMap.new(gemspec.name, gemspec.version).resolved?
|
126
|
-
|
127
|
-
rbs_map = RbsMap.new(gemspec.name, gemspec.version, directories: [workspace&.rbs_collection_path])
|
128
|
-
return gempins unless rbs_map.resolved?
|
129
|
-
|
130
|
-
Solargraph.logger.info "Updating #{gemspec.name} #{gemspec.version} from collection"
|
131
|
-
GemPins.combine(gempins, rbs_map)
|
132
|
-
end
|
133
|
-
|
134
275
|
# @param path [String]
|
135
276
|
# @return [::Array<Gem::Specification>, nil]
|
136
277
|
def resolve_path_to_gemspecs path
|
@@ -149,7 +290,7 @@ module Solargraph
|
|
149
290
|
file = "lib/#{path}.rb"
|
150
291
|
gemspec = potential_gemspec if potential_gemspec.files.any? { |gemspec_file| file == gemspec_file }
|
151
292
|
rescue Gem::MissingSpecError
|
152
|
-
|
293
|
+
logger.debug { "Require path #{path} could not be resolved to a gem via find_by_path or guess of #{gem_name_guess}" }
|
153
294
|
[]
|
154
295
|
end
|
155
296
|
end
|
@@ -187,7 +328,7 @@ module Solargraph
|
|
187
328
|
dep ||= Gem::Specification.find_by_name(spec.name, spec.requirement)
|
188
329
|
deps.merge fetch_dependencies(dep) if deps.add?(dep)
|
189
330
|
rescue Gem::MissingSpecError
|
190
|
-
Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.requirement} for #{gemspec.name} not found."
|
331
|
+
Solargraph.logger.warn "Gem dependency #{spec.name} #{spec.requirement} for #{gemspec.name} not found in RubyGems."
|
191
332
|
end.to_a
|
192
333
|
end
|
193
334
|
|
@@ -197,6 +338,11 @@ module Solargraph
|
|
197
338
|
gemspec.dependencies - gemspec.development_dependencies
|
198
339
|
end
|
199
340
|
|
341
|
+
|
342
|
+
def inspect
|
343
|
+
self.class.inspect
|
344
|
+
end
|
345
|
+
|
200
346
|
def gemspecs_required_from_bundler
|
201
347
|
if workspace&.directory && Bundler.definition&.lockfile&.to_s&.start_with?(workspace.directory)
|
202
348
|
# Find only the gems bundler is now using
|