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,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Solargraph
4
- VERSION = '0.58.1'
4
+ VERSION = ENV.fetch('SOLARGRAPH_FORCE_VERSION', '0.59.0.dev.1')
5
5
  end
@@ -1,255 +1,257 @@
1
- # frozen_string_literal: true
2
-
3
- require 'yaml'
4
-
5
- module Solargraph
6
- class Workspace
7
- # Configuration data for a workspace.
8
- #
9
- class Config
10
- # The maximum number of files that can be added to a workspace.
11
- # The workspace's .solargraph.yml can override this value.
12
- MAX_FILES = 5000
13
-
14
- # @return [String]
15
- attr_reader :directory
16
-
17
- # @todo To make JSON strongly typed we'll need a record syntax
18
- # @return [Hash{String => undefined, nil}]
19
- attr_reader :raw_data
20
-
21
- # @param directory [String]
22
- def initialize directory = ''
23
- @directory = File.absolute_path(directory)
24
- @raw_data = config_data
25
- included
26
- excluded
27
- end
28
-
29
- # An array of files included in the workspace (before calculating excluded files).
30
- #
31
- # @return [Array<String>]
32
- def included
33
- return [] if directory.empty? || directory == '*'
34
- @included ||= process_globs(@raw_data['include'])
35
- end
36
-
37
- # An array of files excluded from the workspace.
38
- #
39
- # @return [Array<String>]
40
- def excluded
41
- return [] if directory.empty? || directory == '*'
42
- @excluded ||= process_exclusions(@raw_data['exclude'])
43
- end
44
-
45
- # @param filename [String]
46
- def allow? filename
47
- filename = File.absolute_path(filename, directory)
48
- filename.start_with?(directory) &&
49
- !excluded.include?(filename) &&
50
- excluded_directories.none? { |d| filename.start_with?(d) }
51
- end
52
-
53
- # The calculated array of (included - excluded) files in the workspace.
54
- #
55
- # @return [Array<String>]
56
- def calculated
57
- Solargraph.logger.info "Indexing workspace files in #{directory}" unless @calculated || directory.empty? || directory == '*'
58
- @calculated ||= included - excluded
59
- end
60
-
61
- # An array of domains configured for the workspace.
62
- # A domain is a namespace that the ApiMap should include in the global
63
- # namespace. It's typically used to identify available DSLs.
64
- #
65
- # @return [Array<String>]
66
- # @sg-ignore Need to validate config
67
- def domains
68
- raw_data['domains']
69
- end
70
-
71
- # An array of required paths to add to the workspace.
72
- #
73
- # @return [Array<String>]
74
- # @sg-ignore Need to validate config
75
- def required
76
- raw_data['require']
77
- end
78
-
79
- # An array of load paths for required paths.
80
- #
81
- # @return [Array<String>]
82
- def require_paths
83
- raw_data['require_paths'] || []
84
- end
85
-
86
- # An array of reporters to use for diagnostics.
87
- #
88
- # @sg-ignore Need to validate config
89
- # @return [Array<String>]
90
- def reporters
91
- raw_data['reporters']
92
- end
93
-
94
- # A hash of options supported by the formatter
95
- #
96
- # @sg-ignore Need to validate config
97
- # @return [Hash]
98
- def formatter
99
- raw_data['formatter']
100
- end
101
-
102
- # An array of plugins to require.
103
- #
104
- # @sg-ignore Need to validate config
105
- # @return [Array<String>]
106
- def plugins
107
- raw_data['plugins']
108
- end
109
-
110
- # The maximum number of files to parse from the workspace.
111
- #
112
- # @sg-ignore Need to validate config
113
- # @return [Integer]
114
- def max_files
115
- raw_data['max_files']
116
- end
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
-
127
- private
128
-
129
- # @return [String]
130
- def global_config_path
131
- ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
132
- File.join(Dir.home, '.config', 'solargraph', 'config.yml')
133
- end
134
-
135
- # @return [String]
136
- def workspace_config_path
137
- return '' if @directory.empty?
138
- File.join(@directory, '.solargraph.yml')
139
- end
140
-
141
- # @return [Hash{String => undefined}]
142
- def config_data
143
- workspace_config = read_config(workspace_config_path)
144
- global_config = read_config(global_config_path)
145
-
146
- defaults = default_config
147
- defaults.merge({'exclude' => []}) unless workspace_config.nil?
148
-
149
- defaults
150
- .merge(global_config || {})
151
- .merge(workspace_config || {})
152
- end
153
-
154
- # Read a .solargraph yaml config
155
- #
156
- # @param config_path [String]
157
- # @return [Hash{String => Array, Hash, Integer}, nil]
158
- def read_config config_path = ''
159
- return nil if config_path.empty?
160
- return nil unless File.file?(config_path)
161
- YAML.safe_load(File.read(config_path))
162
- end
163
-
164
- # @return [Hash{String => Array, Hash, Integer}]
165
- def default_config
166
- {
167
- 'include' => ['Rakefile', 'Gemfile', '*.gemspec', '**/*.rb'],
168
- 'exclude' => ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*'],
169
- 'require' => [],
170
- 'domains' => [],
171
- 'reporters' => %w[rubocop require_not_found],
172
- 'formatter' => {
173
- 'rubocop' => {
174
- 'cops' => 'safe',
175
- 'except' => [],
176
- 'only' => [],
177
- 'extra_args' =>[]
178
- }
179
- },
180
- 'type_checker' => {
181
- 'rules' => { }
182
- },
183
- 'require_paths' => [],
184
- 'plugins' => [],
185
- 'max_files' => MAX_FILES
186
- }
187
- end
188
-
189
- # Get an array of files from the provided globs.
190
- #
191
- # @param globs [Array<String>]
192
- # @return [Array<String>]
193
- def process_globs globs
194
- result = globs.flat_map do |glob|
195
- Dir[File.absolute_path(glob, directory)]
196
- .map{ |f| f.gsub(/\\/, '/') }
197
- .select { |f| File.file?(f) }
198
- end
199
- result
200
- end
201
-
202
- # Modify the included files based on excluded directories and get an
203
- # array of additional files to exclude.
204
- #
205
- # @param globs [Array<String>]
206
- # @return [Array<String>]
207
- def process_exclusions globs
208
- remainder = globs.select do |glob|
209
- if glob_is_directory?(glob)
210
- exdir = File.absolute_path(glob_to_directory(glob), directory)
211
- included.delete_if { |file| file.start_with?(exdir) }
212
- false
213
- else
214
- true
215
- end
216
- end
217
- process_globs remainder
218
- end
219
-
220
- # True if the glob translates to a whole directory.
221
- #
222
- # @example
223
- # glob_is_directory?('path/to/dir') # => true
224
- # glob_is_directory?('path/to/dir/**/*) # => true
225
- # glob_is_directory?('path/to/file.txt') # => false
226
- # glob_is_directory?('path/to/*.txt') # => false
227
- #
228
- # @param glob [String]
229
- # @return [Boolean]
230
- def glob_is_directory? glob
231
- File.directory?(glob) || File.directory?(glob_to_directory(glob))
232
- end
233
-
234
- # Translate a glob to a base directory if applicable
235
- #
236
- # @example
237
- # glob_to_directory('path/to/dir/**/*') # => 'path/to/dir'
238
- #
239
- # @param glob [String]
240
- # @return [String]
241
- def glob_to_directory glob
242
- glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
243
- end
244
-
245
- # @return [Array<String>]
246
- def excluded_directories
247
- # @type [Array<String>]
248
- excluded = @raw_data['exclude']
249
- excluded
250
- .select { |g| glob_is_directory?(g) }
251
- .map { |g| File.absolute_path(glob_to_directory(g), directory) }
252
- end
253
- end
254
- end
255
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module Solargraph
6
+ class Workspace
7
+ # Configuration data for a workspace.
8
+ #
9
+ class Config
10
+ # The maximum number of files that can be added to a workspace.
11
+ # The workspace's .solargraph.yml can override this value.
12
+ MAX_FILES = 5000
13
+
14
+ # @return [String]
15
+ attr_reader :directory
16
+
17
+ # @todo Need to validate config
18
+ # @return [Hash{String => undefined, nil}]
19
+ attr_reader :raw_data
20
+
21
+ # @param directory [String]
22
+ def initialize directory = ''
23
+ @directory = File.absolute_path(directory)
24
+ @raw_data = config_data
25
+ included
26
+ excluded
27
+ end
28
+
29
+ # An array of files included in the workspace (before calculating excluded files).
30
+ #
31
+ # @return [Array<String>]
32
+ def included
33
+ return [] if directory.empty? || directory == '*'
34
+ @included ||= process_globs(@raw_data['include'])
35
+ end
36
+
37
+ # An array of files excluded from the workspace.
38
+ #
39
+ # @return [Array<String>]
40
+ def excluded
41
+ return [] if directory.empty? || directory == '*'
42
+ @excluded ||= process_exclusions(@raw_data['exclude'])
43
+ end
44
+
45
+ # @param filename [String]
46
+ def allow? filename
47
+ filename = File.absolute_path(filename, directory)
48
+ filename.start_with?(directory) &&
49
+ !excluded.include?(filename) &&
50
+ excluded_directories.none? { |d| filename.start_with?(d) }
51
+ end
52
+
53
+ # The calculated array of (included - excluded) files in the workspace.
54
+ #
55
+ # @return [Array<String>]
56
+ def calculated
57
+ Solargraph.logger.info "Indexing workspace files in #{directory}" unless @calculated || directory.empty? || directory == '*'
58
+ @calculated ||= included - excluded
59
+ end
60
+
61
+ # An array of domains configured for the workspace.
62
+ # A domain is a namespace that the ApiMap should include in the global
63
+ # namespace. It's typically used to identify available DSLs.
64
+ #
65
+ # @return [Array<String>]
66
+ # @sg-ignore Need to validate config
67
+ def domains
68
+ raw_data['domains']
69
+ end
70
+
71
+ # An array of required paths to add to the workspace.
72
+ #
73
+ # @return [Array<String>]
74
+ # @sg-ignore Need to validate config
75
+ def required
76
+ raw_data['require']
77
+ end
78
+
79
+ # An array of load paths for required paths.
80
+ #
81
+ # @sg-ignore Need to validate config
82
+ # @return [Array<String>]
83
+ # @sg-ignore Need to validate config
84
+ def require_paths
85
+ raw_data['require_paths'] || []
86
+ end
87
+
88
+ # An array of reporters to use for diagnostics.
89
+ #
90
+ # @sg-ignore Need to validate config
91
+ # @return [Array<String>]
92
+ def reporters
93
+ raw_data['reporters']
94
+ end
95
+
96
+ # A hash of options supported by the formatter
97
+ #
98
+ # @sg-ignore Need to validate config
99
+ # @return [Hash]
100
+ def formatter
101
+ raw_data['formatter']
102
+ end
103
+
104
+ # An array of plugins to require.
105
+ #
106
+ # @sg-ignore Need to validate config
107
+ # @return [Array<String>]
108
+ def plugins
109
+ raw_data['plugins']
110
+ end
111
+
112
+ # The maximum number of files to parse from the workspace.
113
+ #
114
+ # @sg-ignore Need to validate config
115
+ # @return [Integer]
116
+ def max_files
117
+ raw_data['max_files']
118
+ end
119
+
120
+ # @return [Hash{Symbol => Symbol}]
121
+ def type_checker_rules
122
+ # @type [Hash{String => String}]
123
+ raw_rules = raw_data.fetch('type_checker', {}).fetch('rules', {})
124
+ raw_rules.to_h do |k, v|
125
+ [k.to_sym, v.to_sym]
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ # @return [String]
132
+ def global_config_path
133
+ ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
134
+ File.join(Dir.home, '.config', 'solargraph', 'config.yml')
135
+ end
136
+
137
+ # @return [String]
138
+ def workspace_config_path
139
+ return '' if @directory.empty?
140
+ File.join(@directory, '.solargraph.yml')
141
+ end
142
+
143
+ # @return [Hash{String => undefined}]
144
+ def config_data
145
+ workspace_config = read_config(workspace_config_path)
146
+ global_config = read_config(global_config_path)
147
+
148
+ defaults = default_config
149
+ defaults.merge({'exclude' => []}) unless workspace_config.nil?
150
+
151
+ defaults
152
+ .merge(global_config || {})
153
+ .merge(workspace_config || {})
154
+ end
155
+
156
+ # Read a .solargraph yaml config
157
+ #
158
+ # @param config_path [String]
159
+ # @return [Hash{String => Array, Hash, Integer}, nil]
160
+ def read_config config_path = ''
161
+ return nil if config_path.empty?
162
+ return nil unless File.file?(config_path)
163
+ YAML.safe_load(File.read(config_path))
164
+ end
165
+
166
+ # @return [Hash{String => Array, Hash, Integer}]
167
+ def default_config
168
+ {
169
+ 'include' => ['Rakefile', 'Gemfile', '*.gemspec', '**/*.rb'],
170
+ 'exclude' => ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*'],
171
+ 'require' => [],
172
+ 'domains' => [],
173
+ 'reporters' => %w[rubocop require_not_found],
174
+ 'formatter' => {
175
+ 'rubocop' => {
176
+ 'cops' => 'safe',
177
+ 'except' => [],
178
+ 'only' => [],
179
+ 'extra_args' =>[]
180
+ }
181
+ },
182
+ 'type_checker' => {
183
+ 'rules' => { }
184
+ },
185
+ 'require_paths' => [],
186
+ 'plugins' => [],
187
+ 'max_files' => MAX_FILES
188
+ }
189
+ end
190
+
191
+ # Get an array of files from the provided globs.
192
+ #
193
+ # @param globs [Array<String>]
194
+ # @return [Array<String>]
195
+ def process_globs globs
196
+ result = globs.flat_map do |glob|
197
+ Dir[File.absolute_path(glob, directory)]
198
+ .map{ |f| f.gsub(/\\/, '/') }
199
+ .select { |f| File.file?(f) }
200
+ end
201
+ result
202
+ end
203
+
204
+ # Modify the included files based on excluded directories and get an
205
+ # array of additional files to exclude.
206
+ #
207
+ # @param globs [Array<String>]
208
+ # @return [Array<String>]
209
+ def process_exclusions globs
210
+ remainder = globs.select do |glob|
211
+ if glob_is_directory?(glob)
212
+ exdir = File.absolute_path(glob_to_directory(glob), directory)
213
+ included.delete_if { |file| file.start_with?(exdir) }
214
+ false
215
+ else
216
+ true
217
+ end
218
+ end
219
+ process_globs remainder
220
+ end
221
+
222
+ # True if the glob translates to a whole directory.
223
+ #
224
+ # @example
225
+ # glob_is_directory?('path/to/dir') # => true
226
+ # glob_is_directory?('path/to/dir/**/*) # => true
227
+ # glob_is_directory?('path/to/file.txt') # => false
228
+ # glob_is_directory?('path/to/*.txt') # => false
229
+ #
230
+ # @param glob [String]
231
+ # @return [Boolean]
232
+ def glob_is_directory? glob
233
+ File.directory?(glob) || File.directory?(glob_to_directory(glob))
234
+ end
235
+
236
+ # Translate a glob to a base directory if applicable
237
+ #
238
+ # @example
239
+ # glob_to_directory('path/to/dir/**/*') # => 'path/to/dir'
240
+ #
241
+ # @param glob [String]
242
+ # @return [String]
243
+ def glob_to_directory glob
244
+ glob.gsub(/(\/\*|\/\*\*\/\*\*?)$/, '')
245
+ end
246
+
247
+ # @return [Array<String>]
248
+ def excluded_directories
249
+ # @type [Array<String>]
250
+ excluded = @raw_data['exclude']
251
+ excluded
252
+ .select { |g| glob_is_directory?(g) }
253
+ .map { |g| File.absolute_path(glob_to_directory(g), directory) }
254
+ end
255
+ end
256
+ end
257
+ end