solargraph 0.58.1 → 0.59.0.dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.github/workflows/linting.yml +4 -5
  4. data/.github/workflows/plugins.yml +40 -36
  5. data/.github/workflows/rspec.yml +45 -13
  6. data/.github/workflows/typecheck.yml +2 -2
  7. data/.rubocop_todo.yml +27 -49
  8. data/README.md +3 -3
  9. data/Rakefile +1 -0
  10. data/lib/solargraph/api_map/cache.rb +110 -110
  11. data/lib/solargraph/api_map/constants.rb +289 -279
  12. data/lib/solargraph/api_map/index.rb +204 -193
  13. data/lib/solargraph/api_map/source_to_yard.rb +109 -97
  14. data/lib/solargraph/api_map/store.rb +387 -384
  15. data/lib/solargraph/api_map.rb +1000 -945
  16. data/lib/solargraph/complex_type/conformance.rb +176 -0
  17. data/lib/solargraph/complex_type/type_methods.rb +242 -228
  18. data/lib/solargraph/complex_type/unique_type.rb +632 -482
  19. data/lib/solargraph/complex_type.rb +549 -444
  20. data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
  21. data/lib/solargraph/convention/data_definition.rb +108 -105
  22. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
  23. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
  24. data/lib/solargraph/convention/struct_definition.rb +168 -164
  25. data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
  26. data/lib/solargraph/diagnostics/rubocop.rb +119 -118
  27. data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
  28. data/lib/solargraph/diagnostics/type_check.rb +56 -55
  29. data/lib/solargraph/doc_map.rb +200 -439
  30. data/lib/solargraph/equality.rb +34 -34
  31. data/lib/solargraph/gem_pins.rb +97 -98
  32. data/lib/solargraph/language_server/host/dispatch.rb +131 -130
  33. data/lib/solargraph/language_server/host/message_worker.rb +113 -112
  34. data/lib/solargraph/language_server/host/sources.rb +100 -99
  35. data/lib/solargraph/language_server/host.rb +883 -878
  36. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +109 -114
  37. data/lib/solargraph/language_server/message/extended/document.rb +24 -23
  38. data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
  39. data/lib/solargraph/language_server/message/text_document/definition.rb +42 -40
  40. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +28 -26
  41. data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
  42. data/lib/solargraph/language_server/message/text_document/hover.rb +60 -58
  43. data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
  44. data/lib/solargraph/language_server/message/text_document/type_definition.rb +27 -25
  45. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +25 -23
  46. data/lib/solargraph/library.rb +729 -683
  47. data/lib/solargraph/location.rb +87 -82
  48. data/lib/solargraph/logging.rb +57 -37
  49. data/lib/solargraph/parser/comment_ripper.rb +76 -69
  50. data/lib/solargraph/parser/flow_sensitive_typing.rb +483 -255
  51. data/lib/solargraph/parser/node_processor/base.rb +122 -92
  52. data/lib/solargraph/parser/node_processor.rb +63 -62
  53. data/lib/solargraph/parser/parser_gem/class_methods.rb +167 -149
  54. data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
  55. data/lib/solargraph/parser/parser_gem/node_methods.rb +506 -486
  56. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
  57. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
  58. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
  59. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +46 -46
  60. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
  61. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
  62. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +41 -40
  63. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
  64. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
  65. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
  66. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  67. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
  68. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
  69. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +53 -52
  70. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +296 -291
  71. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  72. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
  73. data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
  74. data/lib/solargraph/parser/region.rb +75 -69
  75. data/lib/solargraph/parser/snippet.rb +17 -17
  76. data/lib/solargraph/pin/base.rb +761 -729
  77. data/lib/solargraph/pin/base_variable.rb +418 -126
  78. data/lib/solargraph/pin/block.rb +126 -104
  79. data/lib/solargraph/pin/breakable.rb +13 -9
  80. data/lib/solargraph/pin/callable.rb +278 -231
  81. data/lib/solargraph/pin/closure.rb +68 -72
  82. data/lib/solargraph/pin/common.rb +94 -79
  83. data/lib/solargraph/pin/compound_statement.rb +55 -0
  84. data/lib/solargraph/pin/conversions.rb +124 -123
  85. data/lib/solargraph/pin/delegated_method.rb +131 -120
  86. data/lib/solargraph/pin/documenting.rb +115 -114
  87. data/lib/solargraph/pin/instance_variable.rb +38 -34
  88. data/lib/solargraph/pin/keyword.rb +16 -20
  89. data/lib/solargraph/pin/local_variable.rb +31 -75
  90. data/lib/solargraph/pin/method.rb +720 -672
  91. data/lib/solargraph/pin/method_alias.rb +42 -34
  92. data/lib/solargraph/pin/namespace.rb +121 -115
  93. data/lib/solargraph/pin/parameter.rb +338 -275
  94. data/lib/solargraph/pin/proxy_type.rb +40 -39
  95. data/lib/solargraph/pin/reference/override.rb +47 -47
  96. data/lib/solargraph/pin/reference/superclass.rb +17 -15
  97. data/lib/solargraph/pin/reference.rb +41 -39
  98. data/lib/solargraph/pin/search.rb +62 -61
  99. data/lib/solargraph/pin/signature.rb +69 -61
  100. data/lib/solargraph/pin/symbol.rb +53 -53
  101. data/lib/solargraph/pin/until.rb +18 -18
  102. data/lib/solargraph/pin/while.rb +18 -18
  103. data/lib/solargraph/pin.rb +46 -44
  104. data/lib/solargraph/pin_cache.rb +665 -245
  105. data/lib/solargraph/position.rb +118 -119
  106. data/lib/solargraph/range.rb +112 -112
  107. data/lib/solargraph/rbs_map/conversions.rb +846 -823
  108. data/lib/solargraph/rbs_map/core_map.rb +65 -58
  109. data/lib/solargraph/rbs_map/stdlib_map.rb +72 -43
  110. data/lib/solargraph/rbs_map.rb +217 -163
  111. data/lib/solargraph/shell.rb +397 -352
  112. data/lib/solargraph/source/chain/call.rb +372 -337
  113. data/lib/solargraph/source/chain/constant.rb +28 -26
  114. data/lib/solargraph/source/chain/hash.rb +35 -34
  115. data/lib/solargraph/source/chain/if.rb +29 -28
  116. data/lib/solargraph/source/chain/instance_variable.rb +34 -13
  117. data/lib/solargraph/source/chain/literal.rb +53 -48
  118. data/lib/solargraph/source/chain/or.rb +31 -23
  119. data/lib/solargraph/source/chain.rb +294 -291
  120. data/lib/solargraph/source/change.rb +89 -82
  121. data/lib/solargraph/source/cursor.rb +172 -166
  122. data/lib/solargraph/source/source_chainer.rb +204 -194
  123. data/lib/solargraph/source/updater.rb +59 -55
  124. data/lib/solargraph/source.rb +524 -498
  125. data/lib/solargraph/source_map/clip.rb +237 -226
  126. data/lib/solargraph/source_map/data.rb +37 -34
  127. data/lib/solargraph/source_map/mapper.rb +282 -259
  128. data/lib/solargraph/source_map.rb +220 -212
  129. data/lib/solargraph/type_checker/problem.rb +34 -32
  130. data/lib/solargraph/type_checker/rules.rb +157 -84
  131. data/lib/solargraph/type_checker.rb +895 -814
  132. data/lib/solargraph/version.rb +1 -1
  133. data/lib/solargraph/workspace/config.rb +257 -255
  134. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  135. data/lib/solargraph/workspace/require_paths.rb +98 -97
  136. data/lib/solargraph/workspace.rb +362 -220
  137. data/lib/solargraph/yard_map/helpers.rb +45 -44
  138. data/lib/solargraph/yard_map/mapper/to_method.rb +134 -130
  139. data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
  140. data/lib/solargraph/yard_map/mapper.rb +84 -79
  141. data/lib/solargraph/yardoc.rb +97 -87
  142. data/lib/solargraph.rb +126 -105
  143. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  144. data/rbs/fills/tuple/tuple.rbs +28 -0
  145. data/rbs/shims/ast/0/node.rbs +5 -0
  146. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  147. data/rbs_collection.yaml +1 -1
  148. data/solargraph.gemspec +2 -1
  149. metadata +22 -17
  150. data/lib/solargraph/type_checker/checks.rb +0 -124
  151. data/lib/solargraph/type_checker/param_def.rb +0 -37
  152. data/lib/solargraph/yard_map/to_method.rb +0 -89
  153. data/sig/shims/ast/0/node.rbs +0 -5
  154. /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
  155. /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
  156. /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
  157. /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
  158. /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
  159. /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
  160. /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
  161. /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
  162. /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
@@ -1,58 +1,65 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- class RbsMap
5
- # Ruby core pins
6
- #
7
- class CoreMap
8
- include Logging
9
-
10
- def resolved?
11
- true
12
- end
13
-
14
- FILLS_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'rbs', 'fills'))
15
-
16
- def initialize; end
17
-
18
- # @return [Enumerable<Pin::Base>]
19
- def pins
20
- return @pins if @pins
21
-
22
- @pins = []
23
- cache = PinCache.deserialize_core
24
- if cache
25
- @pins.replace cache
26
- else
27
- @pins.concat conversions.pins
28
-
29
- # Avoid RBS::DuplicatedDeclarationError by loading in a different EnvironmentLoader
30
- fill_loader = RBS::EnvironmentLoader.new(core_root: nil, repository: RBS::Repository.new(no_stdlib: false))
31
- fill_loader.add(path: Pathname(FILLS_DIRECTORY))
32
- fill_conversions = Conversions.new(loader: fill_loader)
33
- @pins.concat fill_conversions.pins
34
-
35
- @pins.concat RbsMap::CoreFills::ALL
36
-
37
- processed = ApiMap::Store.new(pins).pins.reject { |p| p.is_a?(Solargraph::Pin::Reference::Override) }
38
- @pins.replace processed
39
-
40
- PinCache.serialize_core @pins
41
- end
42
- @pins
43
- end
44
-
45
- private
46
-
47
- # @return [RBS::EnvironmentLoader]
48
- def loader
49
- @loader ||= RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
50
- end
51
-
52
- # @return [Conversions]
53
- def conversions
54
- @conversions ||= Conversions.new(loader: loader)
55
- end
56
- end
57
- end
58
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ class RbsMap
5
+ # Ruby core pins
6
+ #
7
+ class CoreMap
8
+ include Logging
9
+
10
+ def resolved?
11
+ true
12
+ end
13
+
14
+ FILLS_DIRECTORY = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'rbs', 'fills'))
15
+
16
+ def initialize; end
17
+
18
+ # @param out [IO, nil] output stream for logging
19
+ # @return [Enumerable<Pin::Base>]
20
+ def pins out: $stderr
21
+ return @pins if @pins
22
+ @pins = cache_core(out: out)
23
+ end
24
+
25
+ # @param out [StringIO, IO, nil] output stream for logging
26
+ # @return [Array<Pin::Base>]
27
+ def cache_core out: $stderr
28
+ new_pins = []
29
+ cache = PinCache.deserialize_core
30
+ return cache if cache
31
+ new_pins.concat conversions.pins
32
+
33
+ # Avoid RBS::DuplicatedDeclarationError by loading in a different EnvironmentLoader
34
+ fill_loader = RBS::EnvironmentLoader.new(core_root: nil, repository: RBS::Repository.new(no_stdlib: false))
35
+ fill_loader.add(path: Pathname(FILLS_DIRECTORY))
36
+ out&.puts 'Caching RBS pins for Ruby core'
37
+ fill_conversions = Conversions.new(loader: fill_loader)
38
+ new_pins.concat fill_conversions.pins
39
+
40
+ # add some overrides
41
+ new_pins.concat RbsMap::CoreFills::ALL
42
+
43
+ # process overrides, then remove any which couldn't be resolved
44
+ processed = ApiMap::Store.new(new_pins).pins.reject { |p| p.is_a?(Solargraph::Pin::Reference::Override) }
45
+ new_pins.replace processed
46
+
47
+ PinCache.serialize_core new_pins
48
+
49
+ new_pins
50
+ end
51
+
52
+ private
53
+
54
+ # @return [RBS::EnvironmentLoader]
55
+ def loader
56
+ @loader ||= RBS::EnvironmentLoader.new(repository: RBS::Repository.new(no_stdlib: false))
57
+ end
58
+
59
+ # @return [Conversions]
60
+ def conversions
61
+ @conversions ||= Conversions.new(loader: loader)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -1,43 +1,72 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rbs'
4
-
5
- module Solargraph
6
- class RbsMap
7
- # Ruby stdlib pins
8
- #
9
- class StdlibMap < RbsMap
10
- include Logging
11
-
12
- # @type [Hash{String => RbsMap}]
13
- @stdlib_maps_hash = {}
14
-
15
- # @param library [String]
16
- def initialize library
17
- cached_pins = PinCache.deserialize_stdlib_require library
18
- if cached_pins
19
- @pins = cached_pins
20
- @resolved = true
21
- @loaded = true
22
- logger.debug { "Deserialized #{cached_pins.length} cached pins for stdlib require #{library.inspect}" }
23
- else
24
- super
25
- unless resolved?
26
- @pins = []
27
- logger.info { "Could not resolve #{library.inspect}" }
28
- return
29
- end
30
- generated_pins = pins
31
- logger.debug { "Found #{generated_pins.length} pins for stdlib library #{library}" }
32
- PinCache.serialize_stdlib_require library, generated_pins
33
- end
34
- end
35
-
36
- # @param library [String]
37
- # @return [StdlibMap]
38
- def self.load library
39
- @stdlib_maps_hash[library] ||= StdlibMap.new(library)
40
- end
41
- end
42
- end
43
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'rbs'
4
+
5
+ module Solargraph
6
+ class RbsMap
7
+ # Ruby stdlib pins
8
+ #
9
+ class StdlibMap < RbsMap
10
+ include Logging
11
+
12
+ # @type [Hash{String => RbsMap}]
13
+ @stdlib_maps_hash = {}
14
+
15
+
16
+ # @param rebuild [Boolean] build pins regardless of whether we
17
+ # have cached them already
18
+ # @param library [String]
19
+ # @param out [StringIO, IO, nil] where to log messages
20
+ def initialize library, rebuild: false, out: $stderr
21
+ cached_pins = PinCache.deserialize_stdlib_require library
22
+ if cached_pins && !rebuild
23
+ @pins = cached_pins
24
+ @resolved = true
25
+ @loaded = true
26
+ logger.debug { "Deserialized #{cached_pins.length} cached pins for stdlib require #{library.inspect}" }
27
+ elsif self.class.source.has? library, nil
28
+ super(library, out: out)
29
+ unless resolved?
30
+ @pins = []
31
+ logger.debug { "StdlibMap could not resolve #{library.inspect}" }
32
+ return
33
+ end
34
+ generated_pins = pins
35
+ logger.debug { "Found #{generated_pins.length} pins for stdlib library #{library}" }
36
+ PinCache.serialize_stdlib_require library, generated_pins
37
+ end
38
+ end
39
+
40
+ # @return [RBS::Collection::Sources::Stdlib]
41
+ def self.source
42
+ @source ||= RBS::Collection::Sources::Stdlib.instance
43
+ end
44
+
45
+ # @param name [String]
46
+ # @param version [String, nil]
47
+ # @return [Array<Hash{String => String}>, nil]
48
+ def self.stdlib_dependencies name, version = nil
49
+ if source.has?(name, version)
50
+ # @sg-ignore we are relying on undocumented behavior where
51
+ # passing version=nil gives the latest version it has
52
+ source.dependencies_of(name, version)
53
+ else
54
+ []
55
+ end
56
+ end
57
+
58
+ def resolve_dependencies?
59
+ # there are 'virtual' dependencies for stdlib gems in RBS that
60
+ # aren't represented in the actual gemspecs that we'd
61
+ # otherwise use
62
+ true
63
+ end
64
+
65
+ # @param library [String]
66
+ # @return [StdlibMap]
67
+ def self.load library
68
+ @stdlib_maps_hash[library] ||= StdlibMap.new(library)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,163 +1,217 @@
1
- # frozen_string_literal: true
2
-
3
- require 'digest'
4
- require 'pathname'
5
- require 'rbs'
6
-
7
- module Solargraph
8
- class RbsMap
9
- autoload :Conversions, 'solargraph/rbs_map/conversions'
10
- autoload :CoreMap, 'solargraph/rbs_map/core_map'
11
- autoload :CoreFills, 'solargraph/rbs_map/core_fills'
12
- autoload :StdlibMap, 'solargraph/rbs_map/stdlib_map'
13
-
14
- include Logging
15
-
16
- # @type [Hash{String => RbsMap}]
17
- @@rbs_maps_hash = {}
18
-
19
- attr_reader :library
20
-
21
- attr_reader :rbs_collection_paths
22
-
23
- attr_reader :rbs_collection_config_path
24
-
25
- # @param library [String]
26
- # @param version [String, nil]
27
- # @param rbs_collection_config_path [String, Pathname, nil]
28
- # @param rbs_collection_paths [Array<Pathname, String>]
29
- def initialize library, version = nil, rbs_collection_config_path: nil, rbs_collection_paths: []
30
- if rbs_collection_config_path.nil? && !rbs_collection_paths.empty?
31
- raise 'Please provide rbs_collection_config_path if you provide rbs_collection_paths'
32
- end
33
- @library = library
34
- @version = version
35
- @rbs_collection_config_path = rbs_collection_config_path
36
- @rbs_collection_paths = rbs_collection_paths
37
- add_library loader, library, version
38
- end
39
-
40
- # @return [RBS::EnvironmentLoader]
41
- def loader
42
- @loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
43
- end
44
-
45
- # @return [String] representing the version of the RBS info fetched
46
- # for the given library. Must change when the RBS info is
47
- # updated upstream for the same library and version. May change
48
- # if the config for where information comes form changes.
49
- def cache_key
50
- @hextdigest ||= begin
51
- # @type [String, nil]
52
- data = nil
53
- if rbs_collection_config_path
54
- lockfile_path = RBS::Collection::Config.to_lockfile_path(Pathname.new(rbs_collection_config_path))
55
- if lockfile_path.exist?
56
- collection_config = RBS::Collection::Config.from_path lockfile_path
57
- gem_config = collection_config.gem(library)
58
- data = gem_config&.to_s
59
- end
60
- end
61
- if data.nil? || data.empty?
62
- if resolved?
63
- # definitely came from the gem itself and not elsewhere -
64
- # only one version per gem
65
- 'gem-export'
66
- else
67
- 'unresolved'
68
- end
69
- else
70
- Digest::SHA1.hexdigest(data)
71
- end
72
- end
73
- end
74
-
75
- # @param gemspec [Gem::Specification, Bundler::LazySpecification]
76
- # @param rbs_collection_path [String, Pathname, nil]
77
- # @param rbs_collection_config_path [String, Pathname, nil]
78
- # @return [RbsMap]
79
- def self.from_gemspec gemspec, rbs_collection_path, rbs_collection_config_path
80
- rbs_map = RbsMap.new(gemspec.name, gemspec.version,
81
- rbs_collection_paths: [rbs_collection_path].compact,
82
- rbs_collection_config_path: rbs_collection_config_path)
83
- return rbs_map if rbs_map.resolved?
84
-
85
- # try any version of the gem in the collection
86
- RbsMap.new(gemspec.name, nil,
87
- rbs_collection_paths: [rbs_collection_path].compact,
88
- rbs_collection_config_path: rbs_collection_config_path)
89
- end
90
-
91
- # @return [Array<Pin::Base>]
92
- def pins
93
- @pins ||= resolved? ? conversions.pins : []
94
- end
95
-
96
- # @generic T
97
- # @param path [String]
98
- # @param klass [Class<generic<T>>]
99
- # @return [generic<T>, nil]
100
- def path_pin path, klass = Pin::Base
101
- pin = pins.find { |p| p.path == path }
102
- pin if pin&.is_a?(klass)
103
- end
104
-
105
- # @param path [String]
106
- # @return [Array<Pin::Base>]
107
- def path_pins path
108
- pins.select { |p| p.path == path }
109
- end
110
-
111
- def resolved?
112
- @resolved
113
- end
114
-
115
- # @return [RBS::Repository]
116
- def repository
117
- @repository ||= RBS::Repository.new(no_stdlib: false).tap do |repo|
118
- @rbs_collection_paths.each do |dir|
119
- dir_path = Pathname.new(dir)
120
- repo.add(dir_path) if dir_path.exist? && dir_path.directory?
121
- end
122
- end
123
- end
124
-
125
- # @param library [String]
126
- # @return [RbsMap]
127
- def self.load library
128
- @@rbs_maps_hash[library] ||= RbsMap.new(library)
129
- end
130
-
131
- private
132
-
133
- # @return [RBS::EnvironmentLoader]
134
- def loader
135
- @loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
136
- end
137
-
138
- # @return [Conversions]
139
- def conversions
140
- @conversions ||= Conversions.new(loader: loader)
141
- end
142
-
143
- # @param loader [RBS::EnvironmentLoader]
144
- # @param library [String]
145
- # @param version [String, nil]
146
- # @return [Boolean] true if adding the library succeeded
147
- def add_library loader, library, version
148
- @resolved = if loader.has_library?(library: library, version: version)
149
- loader.add library: library, version: version
150
- logger.debug { "#{short_name} successfully loaded library #{library}:#{version}" }
151
- true
152
- else
153
- logger.info { "#{short_name} did not find data for library #{library}:#{version}" }
154
- false
155
- end
156
- end
157
-
158
- # @return [String]
159
- def short_name
160
- self.class.name.split('::').last
161
- end
162
- end
163
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+ require 'pathname'
5
+ require 'rbs'
6
+
7
+ module Solargraph
8
+ class RbsMap
9
+ autoload :Conversions, 'solargraph/rbs_map/conversions'
10
+ autoload :CoreMap, 'solargraph/rbs_map/core_map'
11
+ autoload :CoreFills, 'solargraph/rbs_map/core_fills'
12
+ autoload :StdlibMap, 'solargraph/rbs_map/stdlib_map'
13
+
14
+ include Logging
15
+
16
+ # @type [Hash{String => RbsMap}]
17
+ @@rbs_maps_hash = {}
18
+
19
+ attr_reader :library
20
+
21
+ attr_reader :rbs_collection_paths
22
+
23
+ attr_reader :rbs_collection_config_path
24
+
25
+ # @param library [String]
26
+ # @param version [String, nil]
27
+ # @param rbs_collection_config_path [String, Pathname, nil]
28
+ # @param rbs_collection_paths [Array<Pathname, String>]
29
+ # @param out [StringIO, IO, nil] where to log messages
30
+ def initialize library, version = nil, rbs_collection_config_path: nil, rbs_collection_paths: [], out: $stderr
31
+ if rbs_collection_config_path.nil? && !rbs_collection_paths.empty?
32
+ raise 'Please provide rbs_collection_config_path if you provide rbs_collection_paths'
33
+ end
34
+ @library = library
35
+ @version = version
36
+ @rbs_collection_config_path = rbs_collection_config_path
37
+ @rbs_collection_paths = rbs_collection_paths
38
+ add_library loader, library, version
39
+ end
40
+
41
+ CACHE_KEY_GEM_EXPORT = 'gem-export'
42
+ CACHE_KEY_UNRESOLVED = 'unresolved'
43
+ CACHE_KEY_STDLIB = 'stdlib'
44
+ CACHE_KEY_LOCAL = 'local'
45
+
46
+ # @param cache_key [String, nil]
47
+ # @return [String, nil] a description of the source of the RBS info
48
+ def self.rbs_source_desc cache_key
49
+ case cache_key
50
+ when CACHE_KEY_GEM_EXPORT
51
+ 'RBS gem export'
52
+ when CACHE_KEY_UNRESOLVED
53
+ nil
54
+ when CACHE_KEY_STDLIB
55
+ 'RBS standard library'
56
+ when CACHE_KEY_LOCAL
57
+ 'local RBS shims'
58
+ else
59
+ 'RBS collection'
60
+ end
61
+ end
62
+
63
+ # @return [RBS::EnvironmentLoader]
64
+ def loader
65
+ @loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
66
+ end
67
+
68
+ # @return [String] representing the version of the RBS info fetched
69
+ # for the given library. Must change when the RBS info is
70
+ # updated upstream for the same library and version. May change
71
+ # if the config for where information comes form changes.
72
+ def cache_key
73
+ return CACHE_KEY_UNRESOLVED unless resolved?
74
+
75
+ @hextdigest ||= begin
76
+ # @type [String, nil]
77
+ data = nil
78
+ # @type gem_config [nil, Hash{String => Hash{String => String}}]
79
+ gem_config = nil
80
+ if rbs_collection_config_path
81
+ # @sg-ignore flow sensitive typing needs to handle attrs
82
+ lockfile_path = RBS::Collection::Config.to_lockfile_path(Pathname.new(rbs_collection_config_path))
83
+ if lockfile_path.exist?
84
+ collection_config = RBS::Collection::Config.from_path lockfile_path
85
+ gem_config = collection_config.gem(library)
86
+ data = gem_config&.to_s
87
+ end
88
+ end
89
+ if gem_config.nil?
90
+ CACHE_KEY_STDLIB
91
+ else
92
+ # @type [String]
93
+ source = gem_config.dig('source', 'type')
94
+ case source
95
+ when 'rubygems'
96
+ CACHE_KEY_GEM_EXPORT
97
+ when 'local'
98
+ CACHE_KEY_LOCAL
99
+ when 'stdlib'
100
+ CACHE_KEY_STDLIB
101
+ else
102
+ # @sg-ignore Need to add nil check here
103
+ Digest::SHA1.hexdigest(data)
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ # @param gemspec [Gem::Specification, Bundler::LazySpecification]
110
+ # @param rbs_collection_path [String, Pathname, nil]
111
+ # @param rbs_collection_config_path [String, Pathname, nil]
112
+ # @return [RbsMap]
113
+ def self.from_gemspec gemspec, rbs_collection_path, rbs_collection_config_path
114
+ # prefers stdlib RBS if available
115
+ rbs_map = RbsMap::StdlibMap.new(gemspec.name)
116
+ return rbs_map if rbs_map.resolved?
117
+
118
+ rbs_map = RbsMap.new(gemspec.name, gemspec.version,
119
+ rbs_collection_paths: [rbs_collection_path].compact,
120
+ rbs_collection_config_path: rbs_collection_config_path)
121
+ return rbs_map if rbs_map.resolved?
122
+
123
+ # try any version of the gem in the collection
124
+ RbsMap.new(gemspec.name, nil,
125
+ rbs_collection_paths: [rbs_collection_path].compact,
126
+ rbs_collection_config_path: rbs_collection_config_path)
127
+ end
128
+
129
+ # @param out [IO, nil] where to log messages
130
+ # @return [Array<Pin::Base>]
131
+ def pins out: $stderr
132
+ @pins ||= if resolved?
133
+ conversions.pins
134
+ else
135
+ []
136
+ end
137
+ end
138
+
139
+ # @generic T
140
+ # @param path [String]
141
+ # @param klass [Class<generic<T>>]
142
+ #
143
+ # @sg-ignore Need to be able to resolve generics based on a
144
+ # Class<generic<T>> param
145
+ # @return [generic<T>, nil]
146
+ def path_pin path, klass = Pin::Base
147
+ pin = pins.find { |p| p.path == path }
148
+ pin if pin&.is_a?(klass)
149
+ end
150
+
151
+ # @param path [String]
152
+ # @return [Array<Pin::Base>]
153
+ def path_pins path
154
+ pins.select { |p| p.path == path }
155
+ end
156
+
157
+ def resolved?
158
+ @resolved
159
+ end
160
+
161
+ # @return [RBS::Repository]
162
+ def repository
163
+ @repository ||= RBS::Repository.new(no_stdlib: false).tap do |repo|
164
+ @rbs_collection_paths.each do |dir|
165
+ dir_path = Pathname.new(dir)
166
+ repo.add(dir_path) if dir_path.exist? && dir_path.directory?
167
+ end
168
+ end
169
+ end
170
+
171
+ # @param library [String]
172
+ # @return [RbsMap]
173
+ def self.load library
174
+ @@rbs_maps_hash[library] ||= RbsMap.new(library)
175
+ end
176
+
177
+ private
178
+
179
+ # @return [RBS::EnvironmentLoader]
180
+ def loader
181
+ @loader ||= RBS::EnvironmentLoader.new(core_root: nil, repository: repository)
182
+ end
183
+
184
+ # @return [Conversions]
185
+ def conversions
186
+ @conversions ||= Conversions.new(loader: loader)
187
+ end
188
+
189
+ def resolve_dependencies?
190
+ # we need to resolve dependencies via gemfile.lock manually for
191
+ # YARD regardless, so use same mechanism here so we don't
192
+ # duplicate work generating pins from dependencies
193
+ false
194
+ end
195
+
196
+ # @param loader [RBS::EnvironmentLoader]
197
+ # @param library [String]
198
+ # @param version [String, nil] the version of the library to load, or nil for any
199
+ # @param out [StringIO, IO, nil] where to log messages
200
+ # @return [Boolean] true if adding the library succeeded
201
+ def add_library loader, library, version, out: $stderr
202
+ @resolved = if loader.has_library?(library: library, version: version)
203
+ loader.add library: library, version: version, resolve_dependencies: resolve_dependencies?
204
+ logger.debug { "#{short_name} successfully loaded library #{library}:#{version}" }
205
+ true
206
+ else
207
+ logger.info { "#{short_name} did not find data for library #{library}:#{version}" }
208
+ false
209
+ end
210
+ end
211
+
212
+ # @return [String]
213
+ def short_name
214
+ self.class.name.split('::').last
215
+ end
216
+ end
217
+ end