solargraph 0.56.0 → 0.58.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.
- checksums.yaml +4 -4
- data/.gitattributes +2 -0
- data/.github/workflows/linting.yml +127 -0
- data/.github/workflows/plugins.yml +183 -7
- data/.github/workflows/rspec.yml +55 -5
- data/.github/workflows/typecheck.yml +6 -3
- data/.gitignore +5 -0
- data/.overcommit.yml +72 -0
- data/.rspec +1 -0
- data/.rubocop.yml +66 -0
- data/.rubocop_todo.yml +1279 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +86 -1
- data/README.md +8 -4
- data/Rakefile +125 -13
- data/bin/solargraph +3 -0
- data/lib/solargraph/api_map/cache.rb +3 -2
- data/lib/solargraph/api_map/constants.rb +279 -0
- data/lib/solargraph/api_map/index.rb +49 -31
- data/lib/solargraph/api_map/source_to_yard.rb +13 -4
- data/lib/solargraph/api_map/store.rb +144 -26
- data/lib/solargraph/api_map.rb +217 -245
- data/lib/solargraph/bench.rb +1 -0
- data/lib/solargraph/complex_type/type_methods.rb +6 -0
- data/lib/solargraph/complex_type/unique_type.rb +19 -12
- data/lib/solargraph/complex_type.rb +24 -3
- data/lib/solargraph/convention/active_support_concern.rb +111 -0
- data/lib/solargraph/convention/base.rb +17 -0
- data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -0
- data/lib/solargraph/convention/data_definition/data_definition_node.rb +91 -0
- data/lib/solargraph/convention/data_definition.rb +105 -0
- data/lib/solargraph/convention/gemspec.rb +3 -2
- data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +2 -1
- data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +4 -2
- data/lib/solargraph/convention/struct_definition.rb +87 -24
- data/lib/solargraph/convention.rb +32 -2
- data/lib/solargraph/diagnostics/rubocop.rb +6 -1
- data/lib/solargraph/diagnostics/rubocop_helpers.rb +5 -3
- data/lib/solargraph/doc_map.rb +52 -18
- data/lib/solargraph/environ.rb +9 -2
- data/lib/solargraph/equality.rb +1 -0
- data/lib/solargraph/gem_pins.rb +21 -11
- data/lib/solargraph/language_server/host/dispatch.rb +2 -0
- data/lib/solargraph/language_server/host/message_worker.rb +3 -0
- data/lib/solargraph/language_server/host.rb +12 -5
- data/lib/solargraph/language_server/message/base.rb +2 -1
- data/lib/solargraph/language_server/message/extended/check_gem_version.rb +1 -1
- data/lib/solargraph/language_server/message/text_document/definition.rb +2 -0
- data/lib/solargraph/language_server/message/text_document/formatting.rb +19 -2
- data/lib/solargraph/language_server/message/text_document/type_definition.rb +1 -0
- data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +2 -0
- data/lib/solargraph/language_server/progress.rb +8 -0
- data/lib/solargraph/language_server/request.rb +4 -1
- data/lib/solargraph/library.rb +50 -33
- data/lib/solargraph/location.rb +3 -0
- data/lib/solargraph/logging.rb +11 -2
- data/lib/solargraph/page.rb +3 -0
- data/lib/solargraph/parser/comment_ripper.rb +8 -1
- data/lib/solargraph/parser/flow_sensitive_typing.rb +33 -5
- data/lib/solargraph/parser/node_processor/base.rb +10 -5
- data/lib/solargraph/parser/node_processor.rb +24 -8
- data/lib/solargraph/parser/parser_gem/class_methods.rb +3 -13
- data/lib/solargraph/parser/parser_gem/flawed_builder.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_chainer.rb +3 -1
- data/lib/solargraph/parser/parser_gem/node_methods.rb +5 -16
- data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +3 -2
- data/lib/solargraph/parser/parser_gem/node_processors/casgn_node.rb +1 -21
- data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +2 -0
- data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +7 -1
- data/lib/solargraph/parser/parser_gem/node_processors/namespace_node.rb +0 -22
- data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +65 -8
- data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +12 -3
- data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +36 -16
- data/lib/solargraph/parser/parser_gem/node_processors/sym_node.rb +1 -0
- data/lib/solargraph/parser/parser_gem/node_processors.rb +4 -0
- data/lib/solargraph/parser/region.rb +3 -0
- data/lib/solargraph/parser/snippet.rb +2 -0
- data/lib/solargraph/pin/base.rb +92 -14
- data/lib/solargraph/pin/base_variable.rb +6 -5
- data/lib/solargraph/pin/block.rb +3 -2
- data/lib/solargraph/pin/callable.rb +14 -1
- data/lib/solargraph/pin/closure.rb +5 -7
- data/lib/solargraph/pin/common.rb +6 -2
- data/lib/solargraph/pin/constant.rb +2 -0
- data/lib/solargraph/pin/local_variable.rb +1 -2
- data/lib/solargraph/pin/method.rb +32 -11
- data/lib/solargraph/pin/method_alias.rb +3 -0
- data/lib/solargraph/pin/parameter.rb +24 -10
- data/lib/solargraph/pin/proxy_type.rb +5 -1
- data/lib/solargraph/pin/reference/override.rb +15 -1
- data/lib/solargraph/pin/reference/superclass.rb +5 -0
- data/lib/solargraph/pin/reference.rb +17 -0
- data/lib/solargraph/pin/search.rb +6 -1
- data/lib/solargraph/pin/signature.rb +2 -0
- data/lib/solargraph/pin/symbol.rb +5 -0
- data/lib/solargraph/pin_cache.rb +64 -4
- data/lib/solargraph/position.rb +3 -0
- data/lib/solargraph/range.rb +5 -0
- data/lib/solargraph/rbs_map/conversions.rb +68 -18
- data/lib/solargraph/rbs_map/core_fills.rb +18 -0
- data/lib/solargraph/rbs_map/core_map.rb +14 -7
- data/lib/solargraph/rbs_map.rb +14 -1
- data/lib/solargraph/shell.rb +85 -1
- data/lib/solargraph/source/chain/call.rb +7 -3
- data/lib/solargraph/source/chain/constant.rb +3 -66
- data/lib/solargraph/source/chain/if.rb +1 -1
- data/lib/solargraph/source/chain/link.rb +11 -2
- data/lib/solargraph/source/chain/or.rb +1 -1
- data/lib/solargraph/source/chain.rb +11 -2
- data/lib/solargraph/source/change.rb +2 -2
- data/lib/solargraph/source/cursor.rb +2 -3
- data/lib/solargraph/source/encoding_fixes.rb +23 -23
- data/lib/solargraph/source/source_chainer.rb +1 -1
- data/lib/solargraph/source.rb +6 -3
- data/lib/solargraph/source_map/clip.rb +18 -26
- data/lib/solargraph/source_map/data.rb +4 -0
- data/lib/solargraph/source_map/mapper.rb +2 -2
- data/lib/solargraph/source_map.rb +28 -16
- data/lib/solargraph/type_checker/param_def.rb +2 -0
- data/lib/solargraph/type_checker/rules.rb +30 -8
- data/lib/solargraph/type_checker.rb +301 -186
- data/lib/solargraph/version.rb +5 -5
- data/lib/solargraph/workspace/config.rb +22 -6
- data/lib/solargraph/workspace/require_paths.rb +97 -0
- data/lib/solargraph/workspace.rb +38 -67
- data/lib/solargraph/yard_map/helpers.rb +29 -1
- data/lib/solargraph/yard_map/mapper/to_constant.rb +5 -5
- data/lib/solargraph/yard_map/mapper/to_method.rb +5 -9
- data/lib/solargraph/yard_map/mapper/to_namespace.rb +8 -7
- data/lib/solargraph/yard_map/to_method.rb +2 -1
- data/lib/solargraph/yardoc.rb +41 -3
- data/lib/solargraph.rb +15 -0
- data/rbs/fills/bundler/0/bundler.rbs +4271 -0
- data/rbs/fills/open3/0/open3.rbs +172 -0
- data/rbs/fills/rubygems/0/basic_specification.rbs +326 -0
- data/rbs/fills/rubygems/0/errors.rbs +364 -0
- data/rbs/fills/rubygems/0/spec_fetcher.rbs +107 -0
- data/rbs/fills/rubygems/0/specification.rbs +1753 -0
- data/rbs/fills/{tuple.rbs → tuple/tuple.rbs} +2 -3
- data/rbs_collection.yaml +4 -4
- data/sig/shims/ast/0/node.rbs +5 -0
- data/sig/shims/ast/2.4/.rbs_meta.yaml +9 -0
- data/sig/shims/ast/2.4/ast.rbs +73 -0
- data/sig/shims/parser/3.2.0.1/builders/default.rbs +195 -0
- data/sig/shims/parser/3.2.0.1/manifest.yaml +7 -0
- data/sig/shims/parser/3.2.0.1/parser.rbs +201 -0
- data/sig/shims/parser/3.2.0.1/polyfill.rbs +4 -0
- data/sig/shims/thor/1.2.0.1/.rbs_meta.yaml +9 -0
- data/sig/shims/thor/1.2.0.1/manifest.yaml +7 -0
- data/sig/shims/thor/1.2.0.1/thor.rbs +17 -0
- data/solargraph.gemspec +26 -5
- metadata +187 -15
- data/lib/.rubocop.yml +0 -22
- data/lib/solargraph/parser/node_methods.rb +0 -97
data/lib/solargraph/version.rb
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Solargraph
|
|
4
|
-
VERSION = '0.
|
|
5
|
-
end
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Solargraph
|
|
4
|
+
VERSION = '0.58.1'
|
|
5
|
+
end
|
|
@@ -14,8 +14,8 @@ module Solargraph
|
|
|
14
14
|
# @return [String]
|
|
15
15
|
attr_reader :directory
|
|
16
16
|
|
|
17
|
-
# @todo To make
|
|
18
|
-
# @return [Hash{String =>
|
|
17
|
+
# @todo To make JSON strongly typed we'll need a record syntax
|
|
18
|
+
# @return [Hash{String => undefined, nil}]
|
|
19
19
|
attr_reader :raw_data
|
|
20
20
|
|
|
21
21
|
# @param directory [String]
|
|
@@ -63,6 +63,7 @@ module Solargraph
|
|
|
63
63
|
# namespace. It's typically used to identify available DSLs.
|
|
64
64
|
#
|
|
65
65
|
# @return [Array<String>]
|
|
66
|
+
# @sg-ignore Need to validate config
|
|
66
67
|
def domains
|
|
67
68
|
raw_data['domains']
|
|
68
69
|
end
|
|
@@ -70,6 +71,7 @@ module Solargraph
|
|
|
70
71
|
# An array of required paths to add to the workspace.
|
|
71
72
|
#
|
|
72
73
|
# @return [Array<String>]
|
|
74
|
+
# @sg-ignore Need to validate config
|
|
73
75
|
def required
|
|
74
76
|
raw_data['require']
|
|
75
77
|
end
|
|
@@ -83,6 +85,7 @@ module Solargraph
|
|
|
83
85
|
|
|
84
86
|
# An array of reporters to use for diagnostics.
|
|
85
87
|
#
|
|
88
|
+
# @sg-ignore Need to validate config
|
|
86
89
|
# @return [Array<String>]
|
|
87
90
|
def reporters
|
|
88
91
|
raw_data['reporters']
|
|
@@ -90,7 +93,7 @@ module Solargraph
|
|
|
90
93
|
|
|
91
94
|
# A hash of options supported by the formatter
|
|
92
95
|
#
|
|
93
|
-
# @sg-ignore
|
|
96
|
+
# @sg-ignore Need to validate config
|
|
94
97
|
# @return [Hash]
|
|
95
98
|
def formatter
|
|
96
99
|
raw_data['formatter']
|
|
@@ -98,6 +101,7 @@ module Solargraph
|
|
|
98
101
|
|
|
99
102
|
# An array of plugins to require.
|
|
100
103
|
#
|
|
104
|
+
# @sg-ignore Need to validate config
|
|
101
105
|
# @return [Array<String>]
|
|
102
106
|
def plugins
|
|
103
107
|
raw_data['plugins']
|
|
@@ -105,12 +109,21 @@ module Solargraph
|
|
|
105
109
|
|
|
106
110
|
# The maximum number of files to parse from the workspace.
|
|
107
111
|
#
|
|
108
|
-
# @sg-ignore
|
|
112
|
+
# @sg-ignore Need to validate config
|
|
109
113
|
# @return [Integer]
|
|
110
114
|
def max_files
|
|
111
115
|
raw_data['max_files']
|
|
112
116
|
end
|
|
113
117
|
|
|
118
|
+
# @return [Hash{Symbol => Symbol}]
|
|
119
|
+
def type_checker_rules
|
|
120
|
+
# @type [Hash{String => String}]
|
|
121
|
+
raw_rules = raw_data.fetch('type_checker', {}).fetch('rules', {})
|
|
122
|
+
raw_rules.to_h do |k, v|
|
|
123
|
+
[k.to_sym, v.to_sym]
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
114
127
|
private
|
|
115
128
|
|
|
116
129
|
# @return [String]
|
|
@@ -125,7 +138,7 @@ module Solargraph
|
|
|
125
138
|
File.join(@directory, '.solargraph.yml')
|
|
126
139
|
end
|
|
127
140
|
|
|
128
|
-
# @return [Hash{String =>
|
|
141
|
+
# @return [Hash{String => undefined}]
|
|
129
142
|
def config_data
|
|
130
143
|
workspace_config = read_config(workspace_config_path)
|
|
131
144
|
global_config = read_config(global_config_path)
|
|
@@ -151,7 +164,7 @@ module Solargraph
|
|
|
151
164
|
# @return [Hash{String => Array, Hash, Integer}]
|
|
152
165
|
def default_config
|
|
153
166
|
{
|
|
154
|
-
'include' => ['**/*.rb'],
|
|
167
|
+
'include' => ['Rakefile', 'Gemfile', '*.gemspec', '**/*.rb'],
|
|
155
168
|
'exclude' => ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*'],
|
|
156
169
|
'require' => [],
|
|
157
170
|
'domains' => [],
|
|
@@ -164,6 +177,9 @@ module Solargraph
|
|
|
164
177
|
'extra_args' =>[]
|
|
165
178
|
}
|
|
166
179
|
},
|
|
180
|
+
'type_checker' => {
|
|
181
|
+
'rules' => { }
|
|
182
|
+
},
|
|
167
183
|
'require_paths' => [],
|
|
168
184
|
'plugins' => [],
|
|
169
185
|
'max_files' => MAX_FILES
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
|
|
5
|
+
module Solargraph
|
|
6
|
+
# A workspace consists of the files in a project's directory and the
|
|
7
|
+
# project's configuration. It provides a Source for each file to be used
|
|
8
|
+
# in an associated Library or ApiMap.
|
|
9
|
+
#
|
|
10
|
+
class Workspace
|
|
11
|
+
# Manages determining which gemspecs are available in a workspace
|
|
12
|
+
class RequirePaths
|
|
13
|
+
attr_reader :directory, :config
|
|
14
|
+
|
|
15
|
+
# @param directory [String, nil]
|
|
16
|
+
# @param config [Config, nil]
|
|
17
|
+
def initialize directory, config
|
|
18
|
+
@directory = directory
|
|
19
|
+
@config = config
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Generate require paths from gemspecs if they exist or assume the default
|
|
23
|
+
# lib directory.
|
|
24
|
+
#
|
|
25
|
+
# @return [Array<String>]
|
|
26
|
+
def generate
|
|
27
|
+
result = require_paths_from_gemspec_files
|
|
28
|
+
return configured_require_paths if result.empty?
|
|
29
|
+
result.concat(config.require_paths.map { |p| File.join(directory, p) }) if config
|
|
30
|
+
result
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
# @return [Array<String>]
|
|
36
|
+
def require_paths_from_gemspec_files
|
|
37
|
+
results = []
|
|
38
|
+
gemspec_file_paths.each do |gemspec_file_path|
|
|
39
|
+
results.concat require_path_from_gemspec_file(gemspec_file_path)
|
|
40
|
+
end
|
|
41
|
+
results
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Get an array of all gemspec files in the workspace.
|
|
45
|
+
#
|
|
46
|
+
# @return [Array<String>]
|
|
47
|
+
def gemspec_file_paths
|
|
48
|
+
return [] if directory.nil?
|
|
49
|
+
@gemspec_file_paths ||= Dir[File.join(directory, '**/*.gemspec')].select do |gs|
|
|
50
|
+
config.nil? || config.allow?(gs)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Get additional require paths defined in the configuration.
|
|
55
|
+
#
|
|
56
|
+
# @return [Array<String>]
|
|
57
|
+
def configured_require_paths
|
|
58
|
+
return ['lib'] unless directory
|
|
59
|
+
return [File.join(directory, 'lib')] if !config || config.require_paths.empty?
|
|
60
|
+
config.require_paths.map { |p| File.join(directory, p) }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Generate require paths from gemspecs if they exist or assume the default
|
|
64
|
+
# lib directory.
|
|
65
|
+
#
|
|
66
|
+
# @param gemspec_file_path [String]
|
|
67
|
+
# @return [Array<String>]
|
|
68
|
+
def require_path_from_gemspec_file gemspec_file_path
|
|
69
|
+
base = File.dirname(gemspec_file_path)
|
|
70
|
+
# HACK: Evaluating gemspec files violates the goal of not running
|
|
71
|
+
# workspace code, but this is how Gem::Specification.load does it
|
|
72
|
+
# anyway.
|
|
73
|
+
cmd = ['ruby', '-e',
|
|
74
|
+
"require 'rubygems'; " \
|
|
75
|
+
"require 'json'; " \
|
|
76
|
+
"spec = eval(File.read('#{gemspec_file_path}'), TOPLEVEL_BINDING, '#{gemspec_file_path}'); " \
|
|
77
|
+
'return unless Gem::Specification === spec; ' \
|
|
78
|
+
'puts({name: spec.name, paths: spec.require_paths}.to_json)']
|
|
79
|
+
o, e, s = Open3.capture3(*cmd)
|
|
80
|
+
if s.success?
|
|
81
|
+
begin
|
|
82
|
+
hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
|
|
83
|
+
return [] if hash.empty?
|
|
84
|
+
hash['paths'].map { |path| File.join(base, path) }
|
|
85
|
+
rescue StandardError => e
|
|
86
|
+
Solargraph.logger.warn "Error reading #{gemspec_file_path}: [#{e.class}] #{e.message}"
|
|
87
|
+
[]
|
|
88
|
+
end
|
|
89
|
+
else
|
|
90
|
+
Solargraph.logger.warn "Error reading #{gemspec_file_path}"
|
|
91
|
+
Solargraph.logger.warn e
|
|
92
|
+
[]
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
data/lib/solargraph/workspace.rb
CHANGED
|
@@ -10,37 +10,52 @@ module Solargraph
|
|
|
10
10
|
#
|
|
11
11
|
class Workspace
|
|
12
12
|
autoload :Config, 'solargraph/workspace/config'
|
|
13
|
+
autoload :RequirePaths, 'solargraph/workspace/require_paths'
|
|
13
14
|
|
|
14
15
|
# @return [String]
|
|
15
16
|
attr_reader :directory
|
|
16
17
|
|
|
17
|
-
# The require paths associated with the workspace.
|
|
18
|
-
#
|
|
19
|
-
# @return [Array<String>]
|
|
20
|
-
attr_reader :require_paths
|
|
21
|
-
|
|
22
18
|
# @return [Array<String>]
|
|
23
19
|
attr_reader :gemnames
|
|
24
20
|
alias source_gems gemnames
|
|
25
21
|
|
|
26
|
-
# @param directory [String]
|
|
22
|
+
# @param directory [String] TODO: Remove '' and '*' special cases
|
|
27
23
|
# @param config [Config, nil]
|
|
28
24
|
# @param server [Hash]
|
|
29
25
|
def initialize directory = '', config = nil, server = {}
|
|
30
|
-
|
|
26
|
+
raise ArgumentError, 'directory must be a String' unless directory.is_a?(String)
|
|
27
|
+
|
|
28
|
+
@directory = if ['*', ''].include?(directory)
|
|
29
|
+
directory
|
|
30
|
+
else
|
|
31
|
+
File.absolute_path(directory)
|
|
32
|
+
end
|
|
31
33
|
@config = config
|
|
32
34
|
@server = server
|
|
33
35
|
load_sources
|
|
34
36
|
@gemnames = []
|
|
35
|
-
@require_paths = generate_require_paths
|
|
36
37
|
require_plugins
|
|
37
38
|
end
|
|
38
39
|
|
|
40
|
+
# The require paths associated with the workspace.
|
|
41
|
+
#
|
|
42
|
+
# @return [Array<String>]
|
|
43
|
+
def require_paths
|
|
44
|
+
# @todo are the semantics of '*' the same as '', meaning 'don't send back any require paths'?
|
|
45
|
+
@require_paths ||= RequirePaths.new(directory_or_nil, config).generate
|
|
46
|
+
end
|
|
47
|
+
|
|
39
48
|
# @return [Solargraph::Workspace::Config]
|
|
40
49
|
def config
|
|
41
50
|
@config ||= Solargraph::Workspace::Config.new(directory)
|
|
42
51
|
end
|
|
43
52
|
|
|
53
|
+
# @param level [Symbol]
|
|
54
|
+
# @return [TypeChecker::Rules]
|
|
55
|
+
def rules(level)
|
|
56
|
+
@rules ||= TypeChecker::Rules.new(level, config.type_checker_rules)
|
|
57
|
+
end
|
|
58
|
+
|
|
44
59
|
# Merge the source. A merge will update the existing source for the file
|
|
45
60
|
# or add it to the sources if the workspace is configured to include it.
|
|
46
61
|
# The source is ignored if the configuration excludes it.
|
|
@@ -111,28 +126,12 @@ module Solargraph
|
|
|
111
126
|
false
|
|
112
127
|
end
|
|
113
128
|
|
|
114
|
-
# True if the workspace contains at least one gemspec file.
|
|
115
|
-
#
|
|
116
|
-
# @return [Boolean]
|
|
117
|
-
def gemspec?
|
|
118
|
-
!gemspecs.empty?
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
# Get an array of all gemspec files in the workspace.
|
|
122
|
-
#
|
|
123
|
-
# @return [Array<String>]
|
|
124
|
-
def gemspecs
|
|
125
|
-
return [] if directory.empty? || directory == '*'
|
|
126
|
-
@gemspecs ||= Dir[File.join(directory, '**/*.gemspec')].select do |gs|
|
|
127
|
-
config.allow? gs
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
129
|
# @return [String, nil]
|
|
132
130
|
def rbs_collection_path
|
|
133
131
|
@gem_rbs_collection ||= read_rbs_collection_path
|
|
134
132
|
end
|
|
135
133
|
|
|
134
|
+
# @return [String, nil]
|
|
136
135
|
def rbs_collection_config_path
|
|
137
136
|
@rbs_collection_config_path ||= begin
|
|
138
137
|
unless directory.empty? || directory == '*'
|
|
@@ -155,6 +154,20 @@ module Solargraph
|
|
|
155
154
|
server['commandPath'] || 'solargraph'
|
|
156
155
|
end
|
|
157
156
|
|
|
157
|
+
# @return [String, nil]
|
|
158
|
+
def directory_or_nil
|
|
159
|
+
return nil if directory.empty? || directory == '*'
|
|
160
|
+
directory
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# True if the workspace has a root Gemfile.
|
|
164
|
+
#
|
|
165
|
+
# @todo Handle projects with custom Bundler/Gemfile setups (see DocMap#gemspecs_required_from_bundler)
|
|
166
|
+
#
|
|
167
|
+
def gemfile?
|
|
168
|
+
directory && File.file?(File.join(directory, 'Gemfile'))
|
|
169
|
+
end
|
|
170
|
+
|
|
158
171
|
private
|
|
159
172
|
|
|
160
173
|
# The language server configuration (or an empty hash if the workspace was
|
|
@@ -184,48 +197,6 @@ module Solargraph
|
|
|
184
197
|
end
|
|
185
198
|
end
|
|
186
199
|
|
|
187
|
-
# Generate require paths from gemspecs if they exist or assume the default
|
|
188
|
-
# lib directory.
|
|
189
|
-
#
|
|
190
|
-
# @return [Array<String>]
|
|
191
|
-
def generate_require_paths
|
|
192
|
-
return configured_require_paths unless gemspec?
|
|
193
|
-
result = []
|
|
194
|
-
gemspecs.each do |file|
|
|
195
|
-
base = File.dirname(file)
|
|
196
|
-
# HACK: Evaluating gemspec files violates the goal of not running
|
|
197
|
-
# workspace code, but this is how Gem::Specification.load does it
|
|
198
|
-
# anyway.
|
|
199
|
-
cmd = ['ruby', '-e', "require 'rubygems'; require 'json'; spec = eval(File.read('#{file}'), TOPLEVEL_BINDING, '#{file}'); return unless Gem::Specification === spec; puts({name: spec.name, paths: spec.require_paths}.to_json)"]
|
|
200
|
-
o, e, s = Open3.capture3(*cmd)
|
|
201
|
-
if s.success?
|
|
202
|
-
begin
|
|
203
|
-
hash = o && !o.empty? ? JSON.parse(o.split("\n").last) : {}
|
|
204
|
-
next if hash.empty?
|
|
205
|
-
@gemnames.push hash['name']
|
|
206
|
-
result.concat(hash['paths'].map { |path| File.join(base, path) })
|
|
207
|
-
rescue StandardError => e
|
|
208
|
-
Solargraph.logger.warn "Error reading #{file}: [#{e.class}] #{e.message}"
|
|
209
|
-
end
|
|
210
|
-
else
|
|
211
|
-
Solargraph.logger.warn "Error reading #{file}"
|
|
212
|
-
Solargraph.logger.warn e
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
result.concat(config.require_paths.map { |p| File.join(directory, p) })
|
|
216
|
-
result.push File.join(directory, 'lib') if result.empty?
|
|
217
|
-
result
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
# Get additional require paths defined in the configuration.
|
|
221
|
-
#
|
|
222
|
-
# @return [Array<String>]
|
|
223
|
-
def configured_require_paths
|
|
224
|
-
return ['lib'] if directory.empty?
|
|
225
|
-
return [File.join(directory, 'lib')] if config.require_paths.empty?
|
|
226
|
-
config.require_paths.map { |p| File.join(directory, p) }
|
|
227
|
-
end
|
|
228
|
-
|
|
229
200
|
# @return [void]
|
|
230
201
|
def require_plugins
|
|
231
202
|
config.plugins.each do |plugin|
|
|
@@ -7,10 +7,38 @@ module Solargraph
|
|
|
7
7
|
# @param spec [Gem::Specification, nil]
|
|
8
8
|
# @return [Solargraph::Location, nil]
|
|
9
9
|
def object_location code_object, spec
|
|
10
|
-
|
|
10
|
+
if spec.nil? || code_object.nil? || code_object.file.nil? || code_object.line.nil?
|
|
11
|
+
if code_object.namespace.is_a?(YARD::CodeObjects::NamespaceObject)
|
|
12
|
+
# If the code object is a namespace, use the namespace's location
|
|
13
|
+
return object_location(code_object.namespace, spec)
|
|
14
|
+
end
|
|
15
|
+
return Solargraph::Location.new(__FILE__, Solargraph::Range.from_to(__LINE__ - 1, 0, __LINE__ - 1, 0))
|
|
16
|
+
end
|
|
11
17
|
file = File.join(spec.full_gem_path, code_object.file)
|
|
12
18
|
Solargraph::Location.new(file, Solargraph::Range.from_to(code_object.line - 1, 0, code_object.line - 1, 0))
|
|
13
19
|
end
|
|
20
|
+
|
|
21
|
+
# @param code_object [YARD::CodeObjects::Base]
|
|
22
|
+
# @param spec [Gem::Specification, nil]
|
|
23
|
+
# @return [Solargraph::Pin::Namespace]
|
|
24
|
+
def create_closure_namespace_for(code_object, spec)
|
|
25
|
+
code_object_for_location = code_object
|
|
26
|
+
# code_object.namespace is sometimes a YARD proxy object pointing to a method path ("Object#new")
|
|
27
|
+
code_object_for_location = code_object.namespace if code_object.namespace.is_a?(YARD::CodeObjects::NamespaceObject)
|
|
28
|
+
namespace_location = object_location(code_object_for_location, spec)
|
|
29
|
+
ns_name = code_object.namespace.to_s
|
|
30
|
+
if ns_name.empty?
|
|
31
|
+
Solargraph::Pin::ROOT_PIN
|
|
32
|
+
else
|
|
33
|
+
Solargraph::Pin::Namespace.new(
|
|
34
|
+
name: ns_name,
|
|
35
|
+
closure: Pin::ROOT_PIN,
|
|
36
|
+
gates: [code_object.namespace.to_s],
|
|
37
|
+
source: :yardoc,
|
|
38
|
+
location: namespace_location
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
14
42
|
end
|
|
15
43
|
end
|
|
16
44
|
end
|
|
@@ -7,12 +7,12 @@ module Solargraph
|
|
|
7
7
|
extend YardMap::Helpers
|
|
8
8
|
|
|
9
9
|
# @param code_object [YARD::CodeObjects::Base]
|
|
10
|
+
# @param closure [Pin::Closure, nil]
|
|
11
|
+
# @param spec [Gem::Specification, nil]
|
|
12
|
+
# @return [Pin::Constant]
|
|
10
13
|
def self.make code_object, closure = nil, spec = nil
|
|
11
|
-
closure ||=
|
|
12
|
-
|
|
13
|
-
gates: [code_object.namespace.to_s],
|
|
14
|
-
source: :yardoc,
|
|
15
|
-
)
|
|
14
|
+
closure ||= create_closure_namespace_for(code_object, spec)
|
|
15
|
+
|
|
16
16
|
Pin::Constant.new(
|
|
17
17
|
location: object_location(code_object, spec),
|
|
18
18
|
closure: closure,
|
|
@@ -11,7 +11,7 @@ module Solargraph
|
|
|
11
11
|
["Rails::Engine", :class, "find_root_with_flag"] => :public
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
# @param code_object [YARD::CodeObjects::
|
|
14
|
+
# @param code_object [YARD::CodeObjects::MethodObject]
|
|
15
15
|
# @param name [String, nil]
|
|
16
16
|
# @param scope [Symbol, nil]
|
|
17
17
|
# @param visibility [Symbol, nil]
|
|
@@ -19,12 +19,7 @@ module Solargraph
|
|
|
19
19
|
# @param spec [Gem::Specification, nil]
|
|
20
20
|
# @return [Solargraph::Pin::Method]
|
|
21
21
|
def self.make code_object, name = nil, scope = nil, visibility = nil, closure = nil, spec = nil
|
|
22
|
-
closure ||=
|
|
23
|
-
name: code_object.namespace.to_s,
|
|
24
|
-
gates: [code_object.namespace.to_s],
|
|
25
|
-
type: code_object.namespace.is_a?(YARD::CodeObjects::ClassObject) ? :class : :module,
|
|
26
|
-
source: :yardoc,
|
|
27
|
-
)
|
|
22
|
+
closure ||= create_closure_namespace_for(code_object, spec)
|
|
28
23
|
location = object_location(code_object, spec)
|
|
29
24
|
name ||= code_object.name.to_s
|
|
30
25
|
return_type = ComplexType::SELF if name == 'new'
|
|
@@ -32,8 +27,8 @@ module Solargraph
|
|
|
32
27
|
final_scope = scope || code_object.scope
|
|
33
28
|
override_key = [closure.path, final_scope, name]
|
|
34
29
|
final_visibility = VISIBILITY_OVERRIDE[override_key]
|
|
35
|
-
final_visibility ||= VISIBILITY_OVERRIDE[
|
|
36
|
-
final_visibility ||= :private if closure.path == 'Kernel' && Kernel.private_instance_methods(false).include?(name)
|
|
30
|
+
final_visibility ||= VISIBILITY_OVERRIDE[[closure.path, final_scope]]
|
|
31
|
+
final_visibility ||= :private if closure.path == 'Kernel' && Kernel.private_instance_methods(false).include?(name.to_sym)
|
|
37
32
|
final_visibility ||= visibility
|
|
38
33
|
final_visibility ||= :private if code_object.module_function? && final_scope == :instance
|
|
39
34
|
final_visibility ||= :public if code_object.module_function? && final_scope == :class
|
|
@@ -90,6 +85,7 @@ module Solargraph
|
|
|
90
85
|
# HACK: Skip `nil` and `self` parameters that are sometimes emitted
|
|
91
86
|
# for methods defined in C
|
|
92
87
|
# See https://github.com/castwide/solargraph/issues/345
|
|
88
|
+
# @sg-ignore https://github.com/castwide/solargraph/pull/1114
|
|
93
89
|
code_object.parameters.select { |a| a[0] && a[0] != 'self' }.map do |a|
|
|
94
90
|
Solargraph::Pin::Parameter.new(
|
|
95
91
|
location: location,
|
|
@@ -7,20 +7,21 @@ module Solargraph
|
|
|
7
7
|
extend YardMap::Helpers
|
|
8
8
|
|
|
9
9
|
# @param code_object [YARD::CodeObjects::NamespaceObject]
|
|
10
|
+
# @param spec [Gem::Specification, nil]
|
|
11
|
+
# @param closure [Pin::Closure, nil]
|
|
12
|
+
# @return [Pin::Namespace]
|
|
10
13
|
def self.make code_object, spec, closure = nil
|
|
11
|
-
closure ||=
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
gates: [code_object.namespace.to_s],
|
|
15
|
-
source: :yardoc,
|
|
16
|
-
)
|
|
14
|
+
closure ||= create_closure_namespace_for(code_object, spec)
|
|
15
|
+
location = object_location(code_object, spec)
|
|
16
|
+
|
|
17
17
|
Pin::Namespace.new(
|
|
18
|
-
location:
|
|
18
|
+
location: location,
|
|
19
19
|
name: code_object.name.to_s,
|
|
20
20
|
comments: code_object.docstring ? code_object.docstring.all.to_s : '',
|
|
21
21
|
type: code_object.is_a?(YARD::CodeObjects::ClassObject) ? :class : :module,
|
|
22
22
|
visibility: code_object.visibility,
|
|
23
23
|
closure: closure,
|
|
24
|
+
gates: closure.gates,
|
|
24
25
|
source: :yardoc,
|
|
25
26
|
)
|
|
26
27
|
end
|
|
@@ -15,6 +15,7 @@ module Solargraph
|
|
|
15
15
|
# HACK: Skip `nil` and `self` parameters that are sometimes emitted
|
|
16
16
|
# for methods defined in C
|
|
17
17
|
# See https://github.com/castwide/solargraph/issues/345
|
|
18
|
+
# @sg-ignore https://github.com/castwide/solargraph/pull/1114
|
|
18
19
|
code_object.parameters.select { |a| a[0] && a[0] != 'self' }.map do |a|
|
|
19
20
|
Solargraph::Pin::Parameter.new(
|
|
20
21
|
location: location,
|
|
@@ -57,7 +58,7 @@ module Solargraph
|
|
|
57
58
|
|
|
58
59
|
include Helpers
|
|
59
60
|
|
|
60
|
-
# @param code_object [YARD::CodeObjects::
|
|
61
|
+
# @param code_object [YARD::CodeObjects::MethodObject]
|
|
61
62
|
# @param name [String, nil]
|
|
62
63
|
# @param scope [Symbol, nil]
|
|
63
64
|
# @param visibility [Symbol, nil]
|
data/lib/solargraph/yardoc.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'open3'
|
|
4
|
+
|
|
3
5
|
module Solargraph
|
|
4
6
|
# Methods for caching and loading YARD documentation for gems.
|
|
5
7
|
#
|
|
@@ -9,15 +11,31 @@ module Solargraph
|
|
|
9
11
|
# Build and cache a gem's yardoc and return the path. If the cache already
|
|
10
12
|
# exists, do nothing and return the path.
|
|
11
13
|
#
|
|
14
|
+
# @param yard_plugins [Array<String>] The names of YARD plugins to use.
|
|
12
15
|
# @param gemspec [Gem::Specification]
|
|
13
16
|
# @return [String] The path to the cached yardoc.
|
|
14
|
-
def cache(gemspec)
|
|
17
|
+
def cache(yard_plugins, gemspec)
|
|
15
18
|
path = PinCache.yardoc_path gemspec
|
|
16
19
|
return path if cached?(gemspec)
|
|
17
20
|
|
|
21
|
+
unless Dir.exist? gemspec.gem_dir
|
|
22
|
+
# Can happen in at least some (old?) RubyGems versions when we
|
|
23
|
+
# have a gemspec describing a standard library like bundler.
|
|
24
|
+
#
|
|
25
|
+
# https://github.com/apiology/solargraph/actions/runs/17650140201/job/50158676842?pr=10
|
|
26
|
+
Solargraph.logger.info { "Bad info from gemspec - #{gemspec.gem_dir} does not exist" }
|
|
27
|
+
return path
|
|
28
|
+
end
|
|
29
|
+
|
|
18
30
|
Solargraph.logger.info "Caching yardoc for #{gemspec.name} #{gemspec.version}"
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
cmd = "yardoc --db #{path} --no-output --plugin solargraph"
|
|
32
|
+
yard_plugins.each { |plugin| cmd << " --plugin #{plugin}" }
|
|
33
|
+
Solargraph.logger.debug { "Running: #{cmd}" }
|
|
34
|
+
# @todo set these up to run in parallel
|
|
35
|
+
stdout_and_stderr_str, status = Open3.capture2e(current_bundle_env_tweaks, cmd, chdir: gemspec.gem_dir)
|
|
36
|
+
unless status.success?
|
|
37
|
+
Solargraph.logger.warn { "YARD failed running #{cmd.inspect} in #{gemspec.gem_dir}" }
|
|
38
|
+
Solargraph.logger.info stdout_and_stderr_str
|
|
21
39
|
end
|
|
22
40
|
path
|
|
23
41
|
end
|
|
@@ -30,6 +48,9 @@ module Solargraph
|
|
|
30
48
|
File.exist?(yardoc)
|
|
31
49
|
end
|
|
32
50
|
|
|
51
|
+
# True if another process is currently building the yardoc cache.
|
|
52
|
+
#
|
|
53
|
+
# @param gemspec [Gem::Specification]
|
|
33
54
|
def processing?(gemspec)
|
|
34
55
|
yardoc = File.join(PinCache.yardoc_path(gemspec), 'processing')
|
|
35
56
|
File.exist?(yardoc)
|
|
@@ -45,5 +66,22 @@ module Solargraph
|
|
|
45
66
|
YARD::Registry.load! PinCache.yardoc_path gemspec
|
|
46
67
|
YARD::Registry.all
|
|
47
68
|
end
|
|
69
|
+
|
|
70
|
+
# If the BUNDLE_GEMFILE environment variable is set, we need to
|
|
71
|
+
# make sure it's an absolute path, as we'll be changing
|
|
72
|
+
# directories.
|
|
73
|
+
#
|
|
74
|
+
# 'bundle exec' sets an absolute path here, but at least the
|
|
75
|
+
# overcommit gem does not, breaking on-the-fly documention with a
|
|
76
|
+
# spawned yardoc command from our current bundle
|
|
77
|
+
#
|
|
78
|
+
# @return [Hash{String => String}] a hash of environment variables to override
|
|
79
|
+
def current_bundle_env_tweaks
|
|
80
|
+
tweaks = {}
|
|
81
|
+
if ENV['BUNDLE_GEMFILE'] && !ENV['BUNDLE_GEMFILE'].empty?
|
|
82
|
+
tweaks['BUNDLE_GEMFILE'] = File.expand_path(ENV['BUNDLE_GEMFILE'])
|
|
83
|
+
end
|
|
84
|
+
tweaks
|
|
85
|
+
end
|
|
48
86
|
end
|
|
49
87
|
end
|
data/lib/solargraph.rb
CHANGED
|
@@ -53,6 +53,8 @@ module Solargraph
|
|
|
53
53
|
dir = File.dirname(__FILE__)
|
|
54
54
|
VIEWS_PATH = File.join(dir, 'solargraph', 'views')
|
|
55
55
|
|
|
56
|
+
CHDIR_MUTEX = Mutex.new
|
|
57
|
+
|
|
56
58
|
# @param type [Symbol] Type of assert.
|
|
57
59
|
def self.asserts_on?(type)
|
|
58
60
|
if ENV['SOLARGRAPH_ASSERTS'].nil? || ENV['SOLARGRAPH_ASSERTS'].empty?
|
|
@@ -65,6 +67,10 @@ module Solargraph
|
|
|
65
67
|
end
|
|
66
68
|
end
|
|
67
69
|
|
|
70
|
+
# @param type [Symbol] The type of assertion to perform.
|
|
71
|
+
# @param msg [String, nil] An optional message to log
|
|
72
|
+
# @param block [Proc] A block that returns a message to log
|
|
73
|
+
# @return [void]
|
|
68
74
|
def self.assert_or_log(type, msg = nil, &block)
|
|
69
75
|
raise (msg || block.call) if asserts_on?(type) && ![:combine_with_visibility].include?(type)
|
|
70
76
|
logger.info msg, &block
|
|
@@ -79,6 +85,11 @@ module Solargraph
|
|
|
79
85
|
|
|
80
86
|
# A helper method that runs Bundler.with_unbundled_env or falls back to
|
|
81
87
|
# Bundler.with_clean_env for earlier versions of Bundler.
|
|
88
|
+
#
|
|
89
|
+
# @generic T
|
|
90
|
+
# @yieldreturn [generic<T>]
|
|
91
|
+
# @sg-ignore dynamic call, but both functions behave the same
|
|
92
|
+
# @return [generic<T>]
|
|
82
93
|
def self.with_clean_env &block
|
|
83
94
|
meth = if Bundler.respond_to?(:with_original_env)
|
|
84
95
|
:with_original_env
|
|
@@ -88,3 +99,7 @@ module Solargraph
|
|
|
88
99
|
Bundler.send meth, &block
|
|
89
100
|
end
|
|
90
101
|
end
|
|
102
|
+
|
|
103
|
+
# Ensure that ParserGem node processors are properly loaded to avoid conflicts
|
|
104
|
+
# with Convention node processors
|
|
105
|
+
require 'solargraph/parser/parser_gem/node_processors'
|