cosmicgraph 0.49.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.
Files changed (259) hide show
  1. checksums.yaml +7 -0
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/rspec.yml +41 -0
  4. data/.gitignore +9 -0
  5. data/.rspec +2 -0
  6. data/.yardopts +2 -0
  7. data/CHANGELOG.md +1150 -0
  8. data/Gemfile +7 -0
  9. data/LICENSE +21 -0
  10. data/README.md +136 -0
  11. data/Rakefile +25 -0
  12. data/SPONSORS.md +15 -0
  13. data/bin/solargraph +5 -0
  14. data/cosmicgraph.gemspec +44 -0
  15. data/lib/.rubocop.yml +22 -0
  16. data/lib/solargraph/api_map/bundler_methods.rb +22 -0
  17. data/lib/solargraph/api_map/cache.rb +70 -0
  18. data/lib/solargraph/api_map/source_to_yard.rb +81 -0
  19. data/lib/solargraph/api_map/store.rb +268 -0
  20. data/lib/solargraph/api_map.rb +704 -0
  21. data/lib/solargraph/bench.rb +27 -0
  22. data/lib/solargraph/cache.rb +51 -0
  23. data/lib/solargraph/complex_type/type_methods.rb +134 -0
  24. data/lib/solargraph/complex_type/unique_type.rb +132 -0
  25. data/lib/solargraph/complex_type.rb +254 -0
  26. data/lib/solargraph/convention/base.rb +33 -0
  27. data/lib/solargraph/convention/gemfile.rb +15 -0
  28. data/lib/solargraph/convention/gemspec.rb +22 -0
  29. data/lib/solargraph/convention/rakefile.rb +17 -0
  30. data/lib/solargraph/convention/rspec.rb +30 -0
  31. data/lib/solargraph/convention.rb +49 -0
  32. data/lib/solargraph/converters/dd.rb +12 -0
  33. data/lib/solargraph/converters/dl.rb +12 -0
  34. data/lib/solargraph/converters/dt.rb +12 -0
  35. data/lib/solargraph/converters/misc.rb +1 -0
  36. data/lib/solargraph/diagnostics/base.rb +29 -0
  37. data/lib/solargraph/diagnostics/require_not_found.rb +53 -0
  38. data/lib/solargraph/diagnostics/rubocop.rb +112 -0
  39. data/lib/solargraph/diagnostics/rubocop_helpers.rb +65 -0
  40. data/lib/solargraph/diagnostics/severities.rb +15 -0
  41. data/lib/solargraph/diagnostics/type_check.rb +54 -0
  42. data/lib/solargraph/diagnostics/update_errors.rb +41 -0
  43. data/lib/solargraph/diagnostics.rb +55 -0
  44. data/lib/solargraph/documentor.rb +76 -0
  45. data/lib/solargraph/environ.rb +45 -0
  46. data/lib/solargraph/language_server/completion_item_kinds.rb +35 -0
  47. data/lib/solargraph/language_server/error_codes.rb +20 -0
  48. data/lib/solargraph/language_server/host/cataloger.rb +56 -0
  49. data/lib/solargraph/language_server/host/diagnoser.rb +89 -0
  50. data/lib/solargraph/language_server/host/dispatch.rb +111 -0
  51. data/lib/solargraph/language_server/host/message_worker.rb +59 -0
  52. data/lib/solargraph/language_server/host/sources.rb +156 -0
  53. data/lib/solargraph/language_server/host.rb +869 -0
  54. data/lib/solargraph/language_server/message/base.rb +89 -0
  55. data/lib/solargraph/language_server/message/cancel_request.rb +13 -0
  56. data/lib/solargraph/language_server/message/client/register_capability.rb +15 -0
  57. data/lib/solargraph/language_server/message/client.rb +11 -0
  58. data/lib/solargraph/language_server/message/completion_item/resolve.rb +58 -0
  59. data/lib/solargraph/language_server/message/completion_item.rb +11 -0
  60. data/lib/solargraph/language_server/message/exit_notification.rb +13 -0
  61. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +100 -0
  62. data/lib/solargraph/language_server/message/extended/document.rb +20 -0
  63. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -0
  64. data/lib/solargraph/language_server/message/extended/download_core.rb +19 -0
  65. data/lib/solargraph/language_server/message/extended/environment.rb +25 -0
  66. data/lib/solargraph/language_server/message/extended/search.rb +20 -0
  67. data/lib/solargraph/language_server/message/extended.rb +21 -0
  68. data/lib/solargraph/language_server/message/initialize.rb +164 -0
  69. data/lib/solargraph/language_server/message/initialized.rb +27 -0
  70. data/lib/solargraph/language_server/message/method_not_found.rb +16 -0
  71. data/lib/solargraph/language_server/message/method_not_implemented.rb +14 -0
  72. data/lib/solargraph/language_server/message/shutdown.rb +13 -0
  73. data/lib/solargraph/language_server/message/text_document/base.rb +19 -0
  74. data/lib/solargraph/language_server/message/text_document/code_action.rb +17 -0
  75. data/lib/solargraph/language_server/message/text_document/completion.rb +59 -0
  76. data/lib/solargraph/language_server/message/text_document/definition.rb +38 -0
  77. data/lib/solargraph/language_server/message/text_document/did_change.rb +15 -0
  78. data/lib/solargraph/language_server/message/text_document/did_close.rb +15 -0
  79. data/lib/solargraph/language_server/message/text_document/did_open.rb +15 -0
  80. data/lib/solargraph/language_server/message/text_document/did_save.rb +17 -0
  81. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +16 -0
  82. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +23 -0
  83. data/lib/solargraph/language_server/message/text_document/folding_range.rb +26 -0
  84. data/lib/solargraph/language_server/message/text_document/formatting.rb +126 -0
  85. data/lib/solargraph/language_server/message/text_document/hover.rb +56 -0
  86. data/lib/solargraph/language_server/message/text_document/on_type_formatting.rb +34 -0
  87. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +11 -0
  88. data/lib/solargraph/language_server/message/text_document/references.rb +16 -0
  89. data/lib/solargraph/language_server/message/text_document/rename.rb +19 -0
  90. data/lib/solargraph/language_server/message/text_document/signature_help.rb +24 -0
  91. data/lib/solargraph/language_server/message/text_document.rb +28 -0
  92. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +30 -0
  93. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +40 -0
  94. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +24 -0
  95. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +23 -0
  96. data/lib/solargraph/language_server/message/workspace.rb +14 -0
  97. data/lib/solargraph/language_server/message.rb +93 -0
  98. data/lib/solargraph/language_server/message_types.rb +14 -0
  99. data/lib/solargraph/language_server/request.rb +24 -0
  100. data/lib/solargraph/language_server/symbol_kinds.rb +36 -0
  101. data/lib/solargraph/language_server/transport/adapter.rb +53 -0
  102. data/lib/solargraph/language_server/transport/data_reader.rb +72 -0
  103. data/lib/solargraph/language_server/transport.rb +13 -0
  104. data/lib/solargraph/language_server/uri_helpers.rb +49 -0
  105. data/lib/solargraph/language_server.rb +19 -0
  106. data/lib/solargraph/library.rb +547 -0
  107. data/lib/solargraph/location.rb +37 -0
  108. data/lib/solargraph/logging.rb +27 -0
  109. data/lib/solargraph/page.rb +83 -0
  110. data/lib/solargraph/parser/comment_ripper.rb +52 -0
  111. data/lib/solargraph/parser/legacy/class_methods.rb +135 -0
  112. data/lib/solargraph/parser/legacy/flawed_builder.rb +16 -0
  113. data/lib/solargraph/parser/legacy/node_chainer.rb +148 -0
  114. data/lib/solargraph/parser/legacy/node_methods.rb +325 -0
  115. data/lib/solargraph/parser/legacy/node_processors/alias_node.rb +23 -0
  116. data/lib/solargraph/parser/legacy/node_processors/args_node.rb +35 -0
  117. data/lib/solargraph/parser/legacy/node_processors/begin_node.rb +15 -0
  118. data/lib/solargraph/parser/legacy/node_processors/block_node.rb +42 -0
  119. data/lib/solargraph/parser/legacy/node_processors/casgn_node.rb +35 -0
  120. data/lib/solargraph/parser/legacy/node_processors/cvasgn_node.rb +23 -0
  121. data/lib/solargraph/parser/legacy/node_processors/def_node.rb +63 -0
  122. data/lib/solargraph/parser/legacy/node_processors/defs_node.rb +36 -0
  123. data/lib/solargraph/parser/legacy/node_processors/gvasgn_node.rb +23 -0
  124. data/lib/solargraph/parser/legacy/node_processors/ivasgn_node.rb +38 -0
  125. data/lib/solargraph/parser/legacy/node_processors/lvasgn_node.rb +28 -0
  126. data/lib/solargraph/parser/legacy/node_processors/namespace_node.rb +39 -0
  127. data/lib/solargraph/parser/legacy/node_processors/orasgn_node.rb +16 -0
  128. data/lib/solargraph/parser/legacy/node_processors/resbody_node.rb +36 -0
  129. data/lib/solargraph/parser/legacy/node_processors/sclass_node.rb +42 -0
  130. data/lib/solargraph/parser/legacy/node_processors/send_node.rb +257 -0
  131. data/lib/solargraph/parser/legacy/node_processors/sym_node.rb +18 -0
  132. data/lib/solargraph/parser/legacy/node_processors.rb +54 -0
  133. data/lib/solargraph/parser/legacy.rb +12 -0
  134. data/lib/solargraph/parser/node_methods.rb +43 -0
  135. data/lib/solargraph/parser/node_processor/base.rb +77 -0
  136. data/lib/solargraph/parser/node_processor.rb +43 -0
  137. data/lib/solargraph/parser/region.rb +66 -0
  138. data/lib/solargraph/parser/rubyvm/class_methods.rb +149 -0
  139. data/lib/solargraph/parser/rubyvm/node_chainer.rb +160 -0
  140. data/lib/solargraph/parser/rubyvm/node_methods.rb +315 -0
  141. data/lib/solargraph/parser/rubyvm/node_processors/alias_node.rb +23 -0
  142. data/lib/solargraph/parser/rubyvm/node_processors/args_node.rb +85 -0
  143. data/lib/solargraph/parser/rubyvm/node_processors/begin_node.rb +15 -0
  144. data/lib/solargraph/parser/rubyvm/node_processors/block_node.rb +42 -0
  145. data/lib/solargraph/parser/rubyvm/node_processors/casgn_node.rb +33 -0
  146. data/lib/solargraph/parser/rubyvm/node_processors/cvasgn_node.rb +23 -0
  147. data/lib/solargraph/parser/rubyvm/node_processors/def_node.rb +75 -0
  148. data/lib/solargraph/parser/rubyvm/node_processors/defs_node.rb +68 -0
  149. data/lib/solargraph/parser/rubyvm/node_processors/gvasgn_node.rb +23 -0
  150. data/lib/solargraph/parser/rubyvm/node_processors/ivasgn_node.rb +38 -0
  151. data/lib/solargraph/parser/rubyvm/node_processors/kw_arg_node.rb +39 -0
  152. data/lib/solargraph/parser/rubyvm/node_processors/lit_node.rb +20 -0
  153. data/lib/solargraph/parser/rubyvm/node_processors/lvasgn_node.rb +27 -0
  154. data/lib/solargraph/parser/rubyvm/node_processors/namespace_node.rb +39 -0
  155. data/lib/solargraph/parser/rubyvm/node_processors/opt_arg_node.rb +26 -0
  156. data/lib/solargraph/parser/rubyvm/node_processors/orasgn_node.rb +15 -0
  157. data/lib/solargraph/parser/rubyvm/node_processors/resbody_node.rb +45 -0
  158. data/lib/solargraph/parser/rubyvm/node_processors/sclass_node.rb +32 -0
  159. data/lib/solargraph/parser/rubyvm/node_processors/scope_node.rb +15 -0
  160. data/lib/solargraph/parser/rubyvm/node_processors/send_node.rb +279 -0
  161. data/lib/solargraph/parser/rubyvm/node_processors/sym_node.rb +18 -0
  162. data/lib/solargraph/parser/rubyvm/node_processors.rb +63 -0
  163. data/lib/solargraph/parser/rubyvm/node_wrapper.rb +47 -0
  164. data/lib/solargraph/parser/rubyvm.rb +40 -0
  165. data/lib/solargraph/parser/snippet.rb +13 -0
  166. data/lib/solargraph/parser.rb +26 -0
  167. data/lib/solargraph/pin/base.rb +299 -0
  168. data/lib/solargraph/pin/base_variable.rb +84 -0
  169. data/lib/solargraph/pin/block.rb +73 -0
  170. data/lib/solargraph/pin/class_variable.rb +8 -0
  171. data/lib/solargraph/pin/closure.rb +37 -0
  172. data/lib/solargraph/pin/common.rb +70 -0
  173. data/lib/solargraph/pin/constant.rb +43 -0
  174. data/lib/solargraph/pin/conversions.rb +92 -0
  175. data/lib/solargraph/pin/documenting.rb +105 -0
  176. data/lib/solargraph/pin/duck_method.rb +16 -0
  177. data/lib/solargraph/pin/global_variable.rb +8 -0
  178. data/lib/solargraph/pin/instance_variable.rb +30 -0
  179. data/lib/solargraph/pin/keyword.rb +15 -0
  180. data/lib/solargraph/pin/keyword_param.rb +8 -0
  181. data/lib/solargraph/pin/local_variable.rb +55 -0
  182. data/lib/solargraph/pin/method.rb +335 -0
  183. data/lib/solargraph/pin/method_alias.rb +31 -0
  184. data/lib/solargraph/pin/namespace.rb +94 -0
  185. data/lib/solargraph/pin/parameter.rb +206 -0
  186. data/lib/solargraph/pin/proxy_type.rb +29 -0
  187. data/lib/solargraph/pin/reference/extend.rb +10 -0
  188. data/lib/solargraph/pin/reference/include.rb +10 -0
  189. data/lib/solargraph/pin/reference/override.rb +29 -0
  190. data/lib/solargraph/pin/reference/prepend.rb +10 -0
  191. data/lib/solargraph/pin/reference/require.rb +14 -0
  192. data/lib/solargraph/pin/reference/superclass.rb +10 -0
  193. data/lib/solargraph/pin/reference.rb +14 -0
  194. data/lib/solargraph/pin/search.rb +56 -0
  195. data/lib/solargraph/pin/signature.rb +23 -0
  196. data/lib/solargraph/pin/singleton.rb +11 -0
  197. data/lib/solargraph/pin/symbol.rb +47 -0
  198. data/lib/solargraph/pin.rb +38 -0
  199. data/lib/solargraph/position.rb +100 -0
  200. data/lib/solargraph/range.rb +95 -0
  201. data/lib/solargraph/rbs_map/conversions.rb +394 -0
  202. data/lib/solargraph/rbs_map/core_fills.rb +61 -0
  203. data/lib/solargraph/rbs_map/core_map.rb +38 -0
  204. data/lib/solargraph/rbs_map/core_signs.rb +33 -0
  205. data/lib/solargraph/rbs_map/stdlib_map.rb +36 -0
  206. data/lib/solargraph/rbs_map.rb +73 -0
  207. data/lib/solargraph/server_methods.rb +16 -0
  208. data/lib/solargraph/shell.rb +234 -0
  209. data/lib/solargraph/source/chain/block_variable.rb +13 -0
  210. data/lib/solargraph/source/chain/call.rb +215 -0
  211. data/lib/solargraph/source/chain/class_variable.rb +13 -0
  212. data/lib/solargraph/source/chain/constant.rb +75 -0
  213. data/lib/solargraph/source/chain/global_variable.rb +13 -0
  214. data/lib/solargraph/source/chain/hash.rb +28 -0
  215. data/lib/solargraph/source/chain/head.rb +19 -0
  216. data/lib/solargraph/source/chain/instance_variable.rb +13 -0
  217. data/lib/solargraph/source/chain/link.rb +71 -0
  218. data/lib/solargraph/source/chain/literal.rb +23 -0
  219. data/lib/solargraph/source/chain/or.rb +23 -0
  220. data/lib/solargraph/source/chain/q_call.rb +11 -0
  221. data/lib/solargraph/source/chain/variable.rb +13 -0
  222. data/lib/solargraph/source/chain/z_super.rb +30 -0
  223. data/lib/solargraph/source/chain.rb +179 -0
  224. data/lib/solargraph/source/change.rb +79 -0
  225. data/lib/solargraph/source/cursor.rb +164 -0
  226. data/lib/solargraph/source/encoding_fixes.rb +23 -0
  227. data/lib/solargraph/source/source_chainer.rb +191 -0
  228. data/lib/solargraph/source/updater.rb +54 -0
  229. data/lib/solargraph/source.rb +522 -0
  230. data/lib/solargraph/source_map/clip.rb +229 -0
  231. data/lib/solargraph/source_map/completion.rb +23 -0
  232. data/lib/solargraph/source_map/mapper.rb +241 -0
  233. data/lib/solargraph/source_map.rb +180 -0
  234. data/lib/solargraph/type_checker/checks.rb +112 -0
  235. data/lib/solargraph/type_checker/param_def.rb +35 -0
  236. data/lib/solargraph/type_checker/problem.rb +32 -0
  237. data/lib/solargraph/type_checker/rules.rb +57 -0
  238. data/lib/solargraph/type_checker.rb +549 -0
  239. data/lib/solargraph/version.rb +5 -0
  240. data/lib/solargraph/views/_method.erb +62 -0
  241. data/lib/solargraph/views/_name_type_tag.erb +10 -0
  242. data/lib/solargraph/views/_namespace.erb +24 -0
  243. data/lib/solargraph/views/document.erb +23 -0
  244. data/lib/solargraph/views/environment.erb +58 -0
  245. data/lib/solargraph/views/layout.erb +44 -0
  246. data/lib/solargraph/views/search.erb +11 -0
  247. data/lib/solargraph/workspace/config.rb +231 -0
  248. data/lib/solargraph/workspace.rb +212 -0
  249. data/lib/solargraph/yard_map/cache.rb +19 -0
  250. data/lib/solargraph/yard_map/helpers.rb +16 -0
  251. data/lib/solargraph/yard_map/mapper/to_constant.rb +25 -0
  252. data/lib/solargraph/yard_map/mapper/to_method.rb +81 -0
  253. data/lib/solargraph/yard_map/mapper/to_namespace.rb +27 -0
  254. data/lib/solargraph/yard_map/mapper.rb +77 -0
  255. data/lib/solargraph/yard_map/to_method.rb +79 -0
  256. data/lib/solargraph/yard_map.rb +301 -0
  257. data/lib/solargraph.rb +69 -0
  258. data/lib/yard-solargraph.rb +33 -0
  259. metadata +587 -0
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Convention
5
+ class Rspec < Base
6
+ def local source_map
7
+ return EMPTY_ENVIRON unless File.basename(source_map.filename) =~ /_spec\.rb$/
8
+ @environ ||= Environ.new(
9
+ requires: ['rspec'],
10
+ domains: ['RSpec::Matchers', 'RSpec::ExpectationGroups'],
11
+ pins: [
12
+ # This override is necessary due to an erroneous @return tag in
13
+ # rspec's YARD documentation.
14
+ # @todo The return types have been fixed (https://github.com/rspec/rspec-expectations/pull/1121)
15
+ Solargraph::Pin::Reference::Override.method_return('RSpec::Matchers#expect', 'RSpec::Expectations::ExpectationTarget')
16
+ ].concat(extras)
17
+ )
18
+ end
19
+
20
+ private
21
+
22
+ def extras
23
+ @@extras ||= SourceMap.load_string(%(
24
+ def describe(*args); end
25
+ def it(*args); end
26
+ )).pins
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module Solargraph
6
+ # Conventions provide a way to modify an ApiMap based on expectations about
7
+ # one of its sources.
8
+ #
9
+ module Convention
10
+ autoload :Base, 'solargraph/convention/base'
11
+ autoload :Gemfile, 'solargraph/convention/gemfile'
12
+ autoload :Rspec, 'solargraph/convention/rspec'
13
+ autoload :Gemspec, 'solargraph/convention/gemspec'
14
+ autoload :Rakefile, 'solargraph/convention/rakefile'
15
+
16
+ @@conventions = Set.new
17
+
18
+ # @param convention [Class<Convention::Base>]
19
+ # @return [void]
20
+ def self.register convention
21
+ @@conventions.add convention.new
22
+ end
23
+
24
+ # @param source_map [SourceMap]
25
+ # @return [Environ]
26
+ def self.for_local(source_map)
27
+ result = Environ.new
28
+ @@conventions.each do |conv|
29
+ result.merge conv.local(source_map)
30
+ end
31
+ result
32
+ end
33
+
34
+ # @param yard_map [YardMap]
35
+ # @return [Environ]
36
+ def self.for_global(yard_map)
37
+ result = Environ.new
38
+ @@conventions.each do |conv|
39
+ result.merge conv.global(yard_map)
40
+ end
41
+ result
42
+ end
43
+
44
+ register Gemfile
45
+ register Gemspec
46
+ register Rspec
47
+ register Rakefile
48
+ end
49
+ end
@@ -0,0 +1,12 @@
1
+ module ReverseMarkdown
2
+ module Converters
3
+ class Dd < Base
4
+ def convert node, state = {}
5
+ content = treat_children(node, state)
6
+ ": #{content.strip}\n"
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ ReverseMarkdown::Converters.register :dd, ReverseMarkdown::Converters::Dd.new
@@ -0,0 +1,12 @@
1
+ module ReverseMarkdown
2
+ module Converters
3
+ class Dl < Base
4
+ def convert node, state = {}
5
+ content = treat_children(node, state).strip
6
+ "\n\n#{content}\n"
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ ReverseMarkdown::Converters.register :dl, ReverseMarkdown::Converters::Dl.new
@@ -0,0 +1,12 @@
1
+ module ReverseMarkdown
2
+ module Converters
3
+ class Dt < Base
4
+ def convert node, state = {}
5
+ content = treat_children(node, state)
6
+ "\n#{content.strip}\n"
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ ReverseMarkdown::Converters.register :dt, ReverseMarkdown::Converters::Dt.new
@@ -0,0 +1 @@
1
+ ReverseMarkdown::Converters.register :tt, ReverseMarkdown::Converters::Code.new
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Diagnostics
5
+ # The base class for diagnostics reporters.
6
+ #
7
+ class Base
8
+ # @return [Array<String>]
9
+ attr_reader :args
10
+
11
+ def initialize *args
12
+ @args = args
13
+ end
14
+
15
+ # Perform a diagnosis on a Source within the context of an ApiMap.
16
+ # The result is an array of hash objects that conform to the LSP's
17
+ # Diagnostic specification.
18
+ #
19
+ # Subclasses should override this method.
20
+ #
21
+ # @param source [Solargraph::Source]
22
+ # @param api_map [Solargraph::ApiMap]
23
+ # @return [Array<Hash>]
24
+ def diagnose source, api_map
25
+ []
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Diagnostics
5
+ # RequireNotFound reports required paths that could not be resolved to
6
+ # either a file in the workspace or a gem.
7
+ #
8
+ class RequireNotFound < Base
9
+ def diagnose source, api_map
10
+ return [] unless source.parsed? && source.synchronized?
11
+ result = []
12
+ refs = {}
13
+ map = api_map.source_map(source.filename)
14
+ map.requires.each { |ref| refs[ref.name] = ref }
15
+ api_map.missing_docs.each do |r|
16
+ next unless refs.key?(r)
17
+ result.push docs_error(r, refs[r].location)
18
+ end
19
+ api_map.unresolved_requires.each do |r|
20
+ next unless refs.key?(r)
21
+ result.push require_error(r, refs[r].location)
22
+ end
23
+ result
24
+ end
25
+
26
+ private
27
+
28
+ # @param path [String]
29
+ # @param location [Location]
30
+ # @return [Hash]
31
+ def docs_error path, location
32
+ {
33
+ range: location.range.to_hash,
34
+ severity: Diagnostics::Severities::WARNING,
35
+ source: 'RequireNotFound',
36
+ message: "YARD docs not found for #{path}"
37
+ }
38
+ end
39
+
40
+ # @param path [String]
41
+ # @param location [Location]
42
+ # @return [Hash]
43
+ def require_error path, location
44
+ {
45
+ range: location.range.to_hash,
46
+ severity: Diagnostics::Severities::WARNING,
47
+ source: 'RequireNotFound',
48
+ message: "Required path #{path} could not be resolved."
49
+ }
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,112 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'stringio'
4
+
5
+ module Solargraph
6
+ module Diagnostics
7
+ # This reporter provides linting through RuboCop.
8
+ #
9
+ class Rubocop < Base
10
+ include RubocopHelpers
11
+
12
+ # Conversion of RuboCop severity names to LSP constants
13
+ SEVERITIES = {
14
+ 'info' => Severities::HINT,
15
+ 'refactor' => Severities::HINT,
16
+ 'convention' => Severities::INFORMATION,
17
+ 'warning' => Severities::WARNING,
18
+ 'error' => Severities::ERROR,
19
+ 'fatal' => Severities::ERROR
20
+ }
21
+
22
+ # @param source [Solargraph::Source]
23
+ # @param _api_map [Solargraph::ApiMap]
24
+ # @return [Array<Hash>]
25
+ def diagnose source, _api_map
26
+ @source = source
27
+ require_rubocop(rubocop_version)
28
+ options, paths = generate_options(source.filename, source.code)
29
+ store = RuboCop::ConfigStore.new
30
+ runner = RuboCop::Runner.new(options, store)
31
+ result = redirect_stdout{ runner.run(paths) }
32
+
33
+ return [] if result.empty?
34
+
35
+ make_array JSON.parse(result)
36
+ rescue RuboCop::ValidationError, RuboCop::ConfigNotFoundError => e
37
+ raise DiagnosticsError, "Error in RuboCop configuration: #{e.message}"
38
+ rescue JSON::ParserError => e
39
+ raise DiagnosticsError, "RuboCop returned invalid data: #{e.message}"
40
+ end
41
+
42
+ private
43
+
44
+ # Extracts the rubocop version from _args_
45
+ #
46
+ # @return [String]
47
+ def rubocop_version
48
+ args.find { |a| a =~ /version=/ }.to_s.split('=').last
49
+ end
50
+
51
+ # @param resp [Hash]
52
+ # @return [Array<Hash>]
53
+ def make_array resp
54
+ diagnostics = []
55
+ resp['files'].each do |file|
56
+ file['offenses'].each do |off|
57
+ diagnostics.push offense_to_diagnostic(off)
58
+ end
59
+ end
60
+ diagnostics
61
+ end
62
+
63
+ # Convert a RuboCop offense to an LSP diagnostic
64
+ #
65
+ # @param off [Hash] Offense received from Rubocop
66
+ # @return [Hash] LSP diagnostic
67
+ def offense_to_diagnostic off
68
+ {
69
+ range: offense_range(off).to_hash,
70
+ # 1 = Error, 2 = Warning, 3 = Information, 4 = Hint
71
+ severity: SEVERITIES[off['severity']],
72
+ source: 'rubocop',
73
+ code: off['cop_name'],
74
+ message: off['message'].gsub(/^#{off['cop_name']}\:/, '')
75
+ }
76
+ end
77
+
78
+ # @param off [Hash]
79
+ # @return [Range]
80
+ def offense_range off
81
+ Range.new(offense_start_position(off), offense_ending_position(off))
82
+ end
83
+
84
+ # @param off [Hash]
85
+ # @return [Position]
86
+ def offense_start_position off
87
+ Position.new(off['location']['start_line'] - 1, off['location']['start_column'] - 1)
88
+ end
89
+
90
+ # @param off [Hash]
91
+ # @return [Position]
92
+ def offense_ending_position off
93
+ if off['location']['start_line'] != off['location']['last_line']
94
+ Position.new(off['location']['start_line'], 0)
95
+ else
96
+ start_line = off['location']['start_line'] - 1
97
+ last_column = off['location']['last_column']
98
+ line = @source.code.lines[start_line]
99
+ col_off = if line.nil? || line.empty?
100
+ 1
101
+ else
102
+ 0
103
+ end
104
+
105
+ Position.new(
106
+ start_line, last_column - col_off
107
+ )
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Diagnostics
5
+ # Utility methods for the RuboCop diagnostics reporter.
6
+ #
7
+ module RubocopHelpers
8
+ module_function
9
+
10
+ # Requires a specific version of rubocop, or the latest installed version
11
+ # if _version_ is `nil`.
12
+ #
13
+ # @param version [String, nil]
14
+ # @raise [InvalidRubocopVersionError] if _version_ is not installed
15
+ def require_rubocop(version = nil)
16
+ begin
17
+ gem_path = Gem::Specification.find_by_name('rubocop', version).full_gem_path
18
+ gem_lib_path = File.join(gem_path, 'lib')
19
+ $LOAD_PATH.unshift(gem_lib_path) unless $LOAD_PATH.include?(gem_lib_path)
20
+ # @todo Gem::MissingSpecVersionError is undocumented for some reason
21
+ # @sg-ignore
22
+ rescue Gem::MissingSpecVersionError => e
23
+ raise InvalidRubocopVersionError,
24
+ "could not find '#{e.name}' (#{e.requirement}) - "\
25
+ "did find: [#{e.specs.map { |s| s.version.version }.join(', ')}]"
26
+ end
27
+ require 'rubocop'
28
+ end
29
+
30
+ # Generate command-line options for the specified filename and code.
31
+ #
32
+ # @param filename [String]
33
+ # @param code [String]
34
+ # @return [Array(Array<String>, Array<String>)]
35
+ def generate_options filename, code
36
+ args = ['-f', 'j', '--force-exclusion', filename]
37
+ base_options = RuboCop::Options.new
38
+ options, paths = base_options.parse(args)
39
+ options[:stdin] = code
40
+ [options, paths]
41
+ end
42
+
43
+ # RuboCop internally uses capitalized drive letters for Windows paths,
44
+ # so we need to convert the paths provided to the command.
45
+ #
46
+ # @param path [String]
47
+ # @return [String]
48
+ def fix_drive_letter path
49
+ return path unless path.match(/^[a-z]:/)
50
+ path[0].upcase + path[1..-1]
51
+ end
52
+
53
+ # @todo This is a smelly way to redirect output, but the RuboCop specs do
54
+ # the same thing.
55
+ # @return [String]
56
+ def redirect_stdout
57
+ redir = StringIO.new
58
+ $stdout = redir
59
+ yield if block_given?
60
+ $stdout = STDOUT
61
+ redir.string
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Diagnostics
5
+ # These severity constants match the DiagnosticSeverity constants in the
6
+ # language server protocol.
7
+ #
8
+ module Severities
9
+ ERROR = 1
10
+ WARNING = 2
11
+ INFORMATION = 3
12
+ HINT = 4
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Diagnostics
5
+ # TypeCheck reports methods with undefined return types, untagged
6
+ # parameters, and invalid param tags.
7
+ #
8
+ class TypeCheck < Base
9
+ def diagnose source, api_map
10
+ # return [] unless args.include?('always') || api_map.workspaced?(source.filename)
11
+ severity = Diagnostics::Severities::ERROR
12
+ level = (args.reverse.find { |a| ['normal', 'typed', 'strict', 'strong'].include?(a) }) || :normal
13
+ checker = Solargraph::TypeChecker.new(source.filename, api_map: api_map, level: level.to_sym)
14
+ checker.problems
15
+ .sort { |a, b| a.location.range.start.line <=> b.location.range.start.line }
16
+ .map do |problem|
17
+ {
18
+ range: extract_first_line(problem.location, source),
19
+ severity: severity,
20
+ source: 'Typecheck',
21
+ message: problem.message
22
+ }
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ # @param location [Location]
29
+ # @param source [Source]
30
+ # @return [Hash]
31
+ def extract_first_line location, source
32
+ return location.range.to_hash if location.range.start.line == location.range.ending.line
33
+ {
34
+ start: {
35
+ line: location.range.start.line,
36
+ character: location.range.start.character
37
+ },
38
+ end: {
39
+ line: location.range.start.line,
40
+ character: last_character(location.range.start, source)
41
+ }
42
+ }
43
+ end
44
+
45
+ # @param position [Solargraph::Position]
46
+ # @param source [Solargraph::Source]
47
+ # @return [Integer]
48
+ def last_character position, source
49
+ cursor = Position.to_offset(source.code, position)
50
+ source.code.index(/[\r\n]/, cursor) || source.code.length
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ module Diagnostics
5
+ class UpdateErrors < Base
6
+ def diagnose source, api_map
7
+ result = []
8
+ combine_ranges(source.code, source.error_ranges).each do |range|
9
+ result.push(
10
+ range: range.to_hash,
11
+ severity: Diagnostics::Severities::ERROR,
12
+ source: 'Solargraph',
13
+ message: 'Syntax error'
14
+ )
15
+ end
16
+ result
17
+ end
18
+
19
+ private
20
+
21
+ # Combine an array of ranges by their starting lines.
22
+ #
23
+ # @param code [String]
24
+ # @param ranges [Array<Range>]
25
+ # @return [Array<Range>]
26
+ def combine_ranges code, ranges
27
+ result = []
28
+ lines = []
29
+ ranges.sort{|a, b| a.start.line <=> b.start.line}.each do |rng|
30
+ next if rng.nil? || lines.include?(rng.start.line)
31
+ lines.push rng.start.line
32
+ next if rng.start.line >= code.lines.length
33
+ scol = code.lines[rng.start.line].index(/[^\s]/) || 0
34
+ ecol = code.lines[rng.start.line].length
35
+ result.push Range.from_to(rng.start.line, scol, rng.start.line, ecol)
36
+ end
37
+ result
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ # The Diagnostics library provides reporters for analyzing problems in code
5
+ # and providing the results to language server clients.
6
+ #
7
+ module Diagnostics
8
+ autoload :Base, 'solargraph/diagnostics/base'
9
+ autoload :Severities, 'solargraph/diagnostics/severities'
10
+ autoload :Rubocop, 'solargraph/diagnostics/rubocop'
11
+ autoload :RubocopHelpers, 'solargraph/diagnostics/rubocop_helpers'
12
+ autoload :RequireNotFound, 'solargraph/diagnostics/require_not_found'
13
+ autoload :UpdateErrors, 'solargraph/diagnostics/update_errors'
14
+ autoload :TypeCheck, 'solargraph/diagnostics/type_check'
15
+
16
+ class << self
17
+ # Add a reporter with a name to identify it in .solargraph.yml files.
18
+ #
19
+ # @param name [String] The name
20
+ # @param klass [Class<Solargraph::Diagnostics::Base>] The class implementation
21
+ # @return [void]
22
+ def register name, klass
23
+ reporter_hash[name] = klass
24
+ end
25
+
26
+ # Get an array of reporter names.
27
+ #
28
+ # @return [Array<String>]
29
+ def reporters
30
+ reporter_hash.keys - ['type_not_defined'] # @todo Hide type_not_defined for now
31
+ end
32
+
33
+ # Find a reporter by name.
34
+ #
35
+ # @param name [String] The name with which the reporter was registered
36
+ # @return [Class<Solargraph::Diagnostics::Base>]
37
+ def reporter name
38
+ reporter_hash[name]
39
+ end
40
+
41
+ private
42
+
43
+ # @return [Hash]
44
+ def reporter_hash
45
+ @reporter_hash ||= {}
46
+ end
47
+ end
48
+
49
+ register 'rubocop', Rubocop
50
+ register 'require_not_found', RequireNotFound
51
+ register 'typecheck', TypeCheck
52
+ register 'update_errors', UpdateErrors
53
+ register 'type_not_defined', TypeCheck # @todo Retained for backwards compatibility
54
+ end
55
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler'
4
+ require 'json'
5
+ require 'open3'
6
+ require 'shellwords'
7
+ require 'yard'
8
+ require 'fileutils'
9
+
10
+ module Solargraph
11
+ class Documentor
12
+ RDOC_GEMS = %w[
13
+ actioncable actionmailbox actionmailer actionpack actiontext actionview
14
+ activejob activemodel activerecord activestorage activesupport railties
15
+ ]
16
+
17
+ def initialize directory, rebuild: false, out: File.new(File::NULL, 'w')
18
+ @directory = directory
19
+ @rebuild = rebuild
20
+ @out = out
21
+ end
22
+
23
+ # @return [Boolean] True if all specs were found and documented.
24
+ def document
25
+ failures = 0
26
+ Documentor.specs_from_bundle(@directory).each_pair do |name, version|
27
+ yd = YARD::Registry.yardoc_file_for_gem(name, "= #{version}")
28
+ if !yd || @rebuild
29
+ FileUtils.safe_unlink File.join(YardMap::CoreDocs.cache_dir, 'gems', "#{name}-#{version}.ser")
30
+ @out.puts "Documenting #{name} #{version}"
31
+ `yard gems #{name} #{version} #{@rebuild ? '--rebuild' : ''}`
32
+ yd = YARD::Registry.yardoc_file_for_gem(name, "= #{version}")
33
+ # HACK: Ignore errors documenting bundler
34
+ if !yd && name != 'bundler'
35
+ @out.puts "#{name} #{version} YARD documentation failed"
36
+ failures += 1
37
+ end
38
+ end
39
+ if yd && RDOC_GEMS.include?(name)
40
+ cache = File.join(Solargraph::YardMap::CoreDocs.cache_dir, 'gems', "#{name}-#{version}", 'yardoc')
41
+ if !File.exist?(cache) || @rebuild
42
+ @out.puts "Caching custom documentation for #{name} #{version}"
43
+ spec = Gem::Specification.find_by_name(name, "= #{version}")
44
+ Solargraph::YardMap::RdocToYard.run(spec)
45
+ end
46
+ end
47
+ end
48
+ if failures > 0
49
+ @out.puts "#{failures} gem#{failures == 1 ? '' : 's'} could not be documented. You might need to run `bundle install`."
50
+ end
51
+ failures == 0
52
+ rescue Solargraph::BundleNotFoundError => e
53
+ @out.puts "[#{e.class}] #{e.message}"
54
+ @out.puts "No bundled gems are available in #{@directory}"
55
+ false
56
+ end
57
+
58
+ # @param directory [String]
59
+ # @return [Hash]
60
+ def self.specs_from_bundle directory
61
+ Solargraph.with_clean_env do
62
+ cmd = [
63
+ 'ruby', '-e',
64
+ "require 'bundler'; require 'json'; Dir.chdir('#{directory}') { puts Bundler.definition.specs_for([:default]).map { |spec| [spec.name, spec.version] }.to_h.to_json }"
65
+ ]
66
+ o, e, s = Open3.capture3(*cmd)
67
+ if s.success?
68
+ o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
69
+ else
70
+ Solargraph.logger.warn e
71
+ raise BundleNotFoundError, "Failed to load gems from bundle at #{directory}"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ # A collection of additional data, such as map pins and required paths, that
5
+ # can be added to an ApiMap.
6
+ #
7
+ # Conventions are used to add Environs.
8
+ #
9
+ class Environ
10
+ # @return [Array<String>]
11
+ attr_reader :requires
12
+
13
+ # @return [Array<String>]
14
+ attr_reader :domains
15
+
16
+ # @return [Array<Pin::Reference::Override>]
17
+ attr_reader :pins
18
+
19
+ # @param requires [Array<String>]
20
+ # @param domains [Array<String>]
21
+ # @param pins [Array<Pin::Base>]
22
+ def initialize requires: [], domains: [], pins: []
23
+ @requires = requires
24
+ @domains = domains
25
+ @pins = pins
26
+ end
27
+
28
+ # @return [self]
29
+ def clear
30
+ domains.clear
31
+ requires.clear
32
+ pins.clear
33
+ self
34
+ end
35
+
36
+ # @param other [Environ]
37
+ # @return [self]
38
+ def merge other
39
+ domains.concat other.domains
40
+ requires.concat other.requires
41
+ pins.concat other.pins
42
+ self
43
+ end
44
+ end
45
+ end