solargraph 0.58.0 → 0.59.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 (219) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +3 -0
  3. data/.gitattributes +2 -0
  4. data/.github/workflows/linting.yml +6 -5
  5. data/.github/workflows/plugins.yml +48 -35
  6. data/.github/workflows/rspec.yml +15 -28
  7. data/.github/workflows/typecheck.yml +3 -2
  8. data/.gitignore +1 -0
  9. data/.rubocop.yml +38 -6
  10. data/.rubocop_todo.yml +53 -966
  11. data/CHANGELOG.md +24 -0
  12. data/Gemfile +3 -1
  13. data/README.md +3 -3
  14. data/Rakefile +26 -23
  15. data/bin/solargraph +9 -8
  16. data/lib/solargraph/api_map/cache.rb +110 -110
  17. data/lib/solargraph/api_map/constants.rb +288 -279
  18. data/lib/solargraph/api_map/index.rb +204 -193
  19. data/lib/solargraph/api_map/source_to_yard.rb +110 -97
  20. data/lib/solargraph/api_map/store.rb +395 -384
  21. data/lib/solargraph/api_map.rb +1029 -945
  22. data/lib/solargraph/bench.rb +44 -45
  23. data/lib/solargraph/complex_type/conformance.rb +176 -0
  24. data/lib/solargraph/complex_type/type_methods.rb +240 -228
  25. data/lib/solargraph/complex_type/unique_type.rb +641 -482
  26. data/lib/solargraph/complex_type.rb +557 -444
  27. data/lib/solargraph/convention/data_definition/data_assignment_node.rb +61 -61
  28. data/lib/solargraph/convention/data_definition/data_definition_node.rb +93 -91
  29. data/lib/solargraph/convention/data_definition.rb +108 -105
  30. data/lib/solargraph/convention/gemfile.rb +15 -15
  31. data/lib/solargraph/convention/gemspec.rb +23 -23
  32. data/lib/solargraph/convention/rakefile.rb +17 -17
  33. data/lib/solargraph/convention/struct_definition/struct_assignment_node.rb +62 -61
  34. data/lib/solargraph/convention/struct_definition/struct_definition_node.rb +103 -102
  35. data/lib/solargraph/convention/struct_definition.rb +168 -164
  36. data/lib/solargraph/convention.rb +78 -78
  37. data/lib/solargraph/converters/dd.rb +19 -17
  38. data/lib/solargraph/converters/dl.rb +17 -15
  39. data/lib/solargraph/converters/dt.rb +17 -15
  40. data/lib/solargraph/converters/misc.rb +3 -1
  41. data/lib/solargraph/diagnostics/require_not_found.rb +54 -53
  42. data/lib/solargraph/diagnostics/rubocop.rb +119 -118
  43. data/lib/solargraph/diagnostics/rubocop_helpers.rb +70 -68
  44. data/lib/solargraph/diagnostics/type_check.rb +56 -55
  45. data/lib/solargraph/diagnostics/update_errors.rb +37 -41
  46. data/lib/solargraph/doc_map.rb +438 -439
  47. data/lib/solargraph/equality.rb +34 -34
  48. data/lib/solargraph/gem_pins.rb +98 -98
  49. data/lib/solargraph/language_server/error_codes.rb +20 -20
  50. data/lib/solargraph/language_server/host/diagnoser.rb +89 -89
  51. data/lib/solargraph/language_server/host/dispatch.rb +130 -130
  52. data/lib/solargraph/language_server/host/message_worker.rb +113 -112
  53. data/lib/solargraph/language_server/host/sources.rb +100 -99
  54. data/lib/solargraph/language_server/host.rb +886 -878
  55. data/lib/solargraph/language_server/message/base.rb +97 -97
  56. data/lib/solargraph/language_server/message/client/register_capability.rb +13 -15
  57. data/lib/solargraph/language_server/message/completion_item/resolve.rb +58 -60
  58. data/lib/solargraph/language_server/message/extended/check_gem_version.rb +108 -114
  59. data/lib/solargraph/language_server/message/extended/document.rb +24 -23
  60. data/lib/solargraph/language_server/message/extended/document_gems.rb +32 -32
  61. data/lib/solargraph/language_server/message/extended/download_core.rb +20 -19
  62. data/lib/solargraph/language_server/message/extended/search.rb +20 -20
  63. data/lib/solargraph/language_server/message/initialize.rb +197 -191
  64. data/lib/solargraph/language_server/message/text_document/completion.rb +58 -56
  65. data/lib/solargraph/language_server/message/text_document/definition.rb +49 -40
  66. data/lib/solargraph/language_server/message/text_document/document_highlight.rb +23 -16
  67. data/lib/solargraph/language_server/message/text_document/document_symbol.rb +36 -26
  68. data/lib/solargraph/language_server/message/text_document/formatting.rb +150 -148
  69. data/lib/solargraph/language_server/message/text_document/hover.rb +58 -58
  70. data/lib/solargraph/language_server/message/text_document/prepare_rename.rb +18 -11
  71. data/lib/solargraph/language_server/message/text_document/references.rb +23 -16
  72. data/lib/solargraph/language_server/message/text_document/rename.rb +26 -19
  73. data/lib/solargraph/language_server/message/text_document/signature_help.rb +25 -24
  74. data/lib/solargraph/language_server/message/text_document/type_definition.rb +33 -25
  75. data/lib/solargraph/language_server/message/workspace/did_change_configuration.rb +41 -35
  76. data/lib/solargraph/language_server/message/workspace/did_change_watched_files.rb +48 -40
  77. data/lib/solargraph/language_server/message/workspace/did_change_workspace_folders.rb +32 -26
  78. data/lib/solargraph/language_server/message/workspace/workspace_symbol.rb +33 -23
  79. data/lib/solargraph/language_server/message.rb +94 -94
  80. data/lib/solargraph/language_server/request.rb +29 -27
  81. data/lib/solargraph/language_server/transport/data_reader.rb +72 -74
  82. data/lib/solargraph/language_server/uri_helpers.rb +49 -49
  83. data/lib/solargraph/library.rb +702 -683
  84. data/lib/solargraph/location.rb +85 -82
  85. data/lib/solargraph/logging.rb +55 -37
  86. data/lib/solargraph/page.rb +92 -92
  87. data/lib/solargraph/parser/comment_ripper.rb +84 -69
  88. data/lib/solargraph/parser/flow_sensitive_typing.rb +471 -255
  89. data/lib/solargraph/parser/node_processor/base.rb +122 -92
  90. data/lib/solargraph/parser/node_processor.rb +63 -62
  91. data/lib/solargraph/parser/parser_gem/class_methods.rb +165 -149
  92. data/lib/solargraph/parser/parser_gem/flawed_builder.rb +19 -19
  93. data/lib/solargraph/parser/parser_gem/node_chainer.rb +191 -166
  94. data/lib/solargraph/parser/parser_gem/node_methods.rb +507 -486
  95. data/lib/solargraph/parser/parser_gem/node_processors/and_node.rb +22 -22
  96. data/lib/solargraph/parser/parser_gem/node_processors/args_node.rb +61 -59
  97. data/lib/solargraph/parser/parser_gem/node_processors/begin_node.rb +24 -15
  98. data/lib/solargraph/parser/parser_gem/node_processors/block_node.rb +45 -46
  99. data/lib/solargraph/parser/parser_gem/node_processors/def_node.rb +60 -53
  100. data/lib/solargraph/parser/parser_gem/node_processors/defs_node.rb +38 -37
  101. data/lib/solargraph/parser/parser_gem/node_processors/if_node.rb +53 -23
  102. data/lib/solargraph/parser/parser_gem/node_processors/ivasgn_node.rb +42 -40
  103. data/lib/solargraph/parser/parser_gem/node_processors/lvasgn_node.rb +30 -29
  104. data/lib/solargraph/parser/parser_gem/node_processors/masgn_node.rb +61 -59
  105. data/lib/solargraph/parser/parser_gem/node_processors/opasgn_node.rb +98 -98
  106. data/lib/solargraph/parser/parser_gem/node_processors/or_node.rb +22 -0
  107. data/lib/solargraph/parser/parser_gem/node_processors/orasgn_node.rb +17 -17
  108. data/lib/solargraph/parser/parser_gem/node_processors/resbody_node.rb +39 -38
  109. data/lib/solargraph/parser/parser_gem/node_processors/sclass_node.rb +51 -52
  110. data/lib/solargraph/parser/parser_gem/node_processors/send_node.rb +302 -291
  111. data/lib/solargraph/parser/parser_gem/node_processors/until_node.rb +29 -29
  112. data/lib/solargraph/parser/parser_gem/node_processors/when_node.rb +23 -0
  113. data/lib/solargraph/parser/parser_gem/node_processors/while_node.rb +33 -29
  114. data/lib/solargraph/parser/parser_gem/node_processors.rb +74 -70
  115. data/lib/solargraph/parser/parser_gem.rb +14 -12
  116. data/lib/solargraph/parser/region.rb +75 -69
  117. data/lib/solargraph/parser/snippet.rb +19 -17
  118. data/lib/solargraph/parser.rb +25 -23
  119. data/lib/solargraph/pin/base.rb +773 -729
  120. data/lib/solargraph/pin/base_variable.rb +375 -126
  121. data/lib/solargraph/pin/block.rb +127 -104
  122. data/lib/solargraph/pin/breakable.rb +15 -9
  123. data/lib/solargraph/pin/callable.rb +275 -231
  124. data/lib/solargraph/pin/closure.rb +69 -72
  125. data/lib/solargraph/pin/common.rb +97 -79
  126. data/lib/solargraph/pin/compound_statement.rb +55 -0
  127. data/lib/solargraph/pin/constant.rb +43 -45
  128. data/lib/solargraph/pin/conversions.rb +129 -123
  129. data/lib/solargraph/pin/delegated_method.rb +131 -120
  130. data/lib/solargraph/pin/documenting.rb +116 -114
  131. data/lib/solargraph/pin/instance_variable.rb +38 -34
  132. data/lib/solargraph/pin/keyword.rb +16 -20
  133. data/lib/solargraph/pin/local_variable.rb +31 -75
  134. data/lib/solargraph/pin/method.rb +724 -672
  135. data/lib/solargraph/pin/method_alias.rb +42 -34
  136. data/lib/solargraph/pin/namespace.rb +122 -115
  137. data/lib/solargraph/pin/parameter.rb +339 -275
  138. data/lib/solargraph/pin/proxy_type.rb +42 -39
  139. data/lib/solargraph/pin/reference/override.rb +47 -47
  140. data/lib/solargraph/pin/reference/superclass.rb +17 -15
  141. data/lib/solargraph/pin/reference/type_alias.rb +16 -0
  142. data/lib/solargraph/pin/reference.rb +59 -39
  143. data/lib/solargraph/pin/search.rb +62 -61
  144. data/lib/solargraph/pin/signature.rb +64 -61
  145. data/lib/solargraph/pin/symbol.rb +54 -53
  146. data/lib/solargraph/pin/until.rb +16 -18
  147. data/lib/solargraph/pin/while.rb +16 -18
  148. data/lib/solargraph/pin.rb +46 -44
  149. data/lib/solargraph/pin_cache.rb +248 -245
  150. data/lib/solargraph/position.rb +139 -119
  151. data/lib/solargraph/range.rb +113 -112
  152. data/lib/solargraph/rbs_map/conversions.rb +952 -823
  153. data/lib/solargraph/rbs_map/core_fills.rb +91 -84
  154. data/lib/solargraph/rbs_map/core_map.rb +65 -58
  155. data/lib/solargraph/rbs_map/stdlib_map.rb +71 -43
  156. data/lib/solargraph/rbs_map.rb +207 -163
  157. data/lib/solargraph/server_methods.rb +16 -16
  158. data/lib/solargraph/shell.rb +555 -352
  159. data/lib/solargraph/source/chain/array.rb +39 -37
  160. data/lib/solargraph/source/chain/call.rb +377 -337
  161. data/lib/solargraph/source/chain/class_variable.rb +13 -13
  162. data/lib/solargraph/source/chain/constant.rb +30 -26
  163. data/lib/solargraph/source/chain/global_variable.rb +13 -13
  164. data/lib/solargraph/source/chain/hash.rb +37 -34
  165. data/lib/solargraph/source/chain/if.rb +30 -28
  166. data/lib/solargraph/source/chain/instance_variable.rb +36 -13
  167. data/lib/solargraph/source/chain/link.rb +99 -109
  168. data/lib/solargraph/source/chain/literal.rb +51 -48
  169. data/lib/solargraph/source/chain/or.rb +29 -23
  170. data/lib/solargraph/source/chain/q_call.rb +13 -11
  171. data/lib/solargraph/source/chain/variable.rb +15 -13
  172. data/lib/solargraph/source/chain/z_super.rb +28 -30
  173. data/lib/solargraph/source/chain.rb +304 -291
  174. data/lib/solargraph/source/change.rb +89 -82
  175. data/lib/solargraph/source/cursor.rb +172 -166
  176. data/lib/solargraph/source/encoding_fixes.rb +22 -23
  177. data/lib/solargraph/source/source_chainer.rb +218 -194
  178. data/lib/solargraph/source/updater.rb +59 -55
  179. data/lib/solargraph/source.rb +522 -498
  180. data/lib/solargraph/source_map/clip.rb +245 -226
  181. data/lib/solargraph/source_map/data.rb +37 -34
  182. data/lib/solargraph/source_map/mapper.rb +286 -259
  183. data/lib/solargraph/source_map.rb +224 -212
  184. data/lib/solargraph/type_checker/problem.rb +34 -32
  185. data/lib/solargraph/type_checker/rules.rb +157 -84
  186. data/lib/solargraph/type_checker.rb +888 -814
  187. data/lib/solargraph/version.rb +5 -5
  188. data/lib/solargraph/workspace/config.rb +258 -255
  189. data/lib/solargraph/workspace/gemspecs.rb +367 -0
  190. data/lib/solargraph/workspace/require_paths.rb +98 -97
  191. data/lib/solargraph/workspace.rb +242 -220
  192. data/lib/solargraph/yard_map/helpers.rb +49 -44
  193. data/lib/solargraph/yard_map/mapper/to_method.rb +136 -130
  194. data/lib/solargraph/yard_map/mapper/to_namespace.rb +32 -31
  195. data/lib/solargraph/yard_map/mapper.rb +84 -79
  196. data/lib/solargraph/yard_map.rb +17 -18
  197. data/lib/solargraph/yard_tags.rb +20 -20
  198. data/lib/solargraph/yardoc.rb +90 -87
  199. data/lib/solargraph.rb +128 -105
  200. data/rbs/fills/rubygems/0/dependency.rbs +193 -0
  201. data/rbs/fills/tuple/tuple.rbs +28 -0
  202. data/rbs/shims/ast/0/node.rbs +5 -0
  203. data/rbs/shims/diff-lcs/1.5/diff-lcs.rbs +11 -0
  204. data/rbs_collection.yaml +1 -1
  205. data/solargraph.gemspec +37 -35
  206. metadata +52 -51
  207. data/lib/solargraph/type_checker/checks.rb +0 -124
  208. data/lib/solargraph/type_checker/param_def.rb +0 -37
  209. data/lib/solargraph/yard_map/to_method.rb +0 -89
  210. data/sig/shims/ast/0/node.rbs +0 -5
  211. /data/{sig → rbs}/shims/ast/2.4/.rbs_meta.yaml +0 -0
  212. /data/{sig → rbs}/shims/ast/2.4/ast.rbs +0 -0
  213. /data/{sig → rbs}/shims/parser/3.2.0.1/builders/default.rbs +0 -0
  214. /data/{sig → rbs}/shims/parser/3.2.0.1/manifest.yaml +0 -0
  215. /data/{sig → rbs}/shims/parser/3.2.0.1/parser.rbs +0 -0
  216. /data/{sig → rbs}/shims/parser/3.2.0.1/polyfill.rbs +0 -0
  217. /data/{sig → rbs}/shims/thor/1.2.0.1/.rbs_meta.yaml +0 -0
  218. /data/{sig → rbs}/shims/thor/1.2.0.1/manifest.yaml +0 -0
  219. /data/{sig → rbs}/shims/thor/1.2.0.1/thor.rbs +0 -0
@@ -1,5 +1,5 @@
1
- # frozen_string_literal: true
2
-
3
- module Solargraph
4
- VERSION = '0.58.0'
5
- end
1
+ # frozen_string_literal: true
2
+
3
+ module Solargraph
4
+ VERSION = ENV.fetch('SOLARGRAPH_FORCE_VERSION', '0.59.0')
5
+ end
@@ -1,255 +1,258 @@
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
+ unless @calculated || directory.empty? || directory == '*'
58
+ Solargraph.logger.info "Indexing workspace files in #{directory}"
59
+ end
60
+ @calculated ||= included - excluded
61
+ end
62
+
63
+ # An array of domains configured for the workspace.
64
+ # A domain is a namespace that the ApiMap should include in the global
65
+ # namespace. It's typically used to identify available DSLs.
66
+ #
67
+ # @return [Array<String>]
68
+ # @sg-ignore Need to validate config
69
+ def domains
70
+ raw_data['domains']
71
+ end
72
+
73
+ # An array of required paths to add to the workspace.
74
+ #
75
+ # @return [Array<String>]
76
+ # @sg-ignore Need to validate config
77
+ def required
78
+ raw_data['require']
79
+ end
80
+
81
+ # An array of load paths for required paths.
82
+ #
83
+ # @sg-ignore Need to validate config
84
+ # @return [Array<String>]
85
+ # @sg-ignore Need to validate config
86
+ def require_paths
87
+ raw_data['require_paths'] || []
88
+ end
89
+
90
+ # An array of reporters to use for diagnostics.
91
+ #
92
+ # @sg-ignore Need to validate config
93
+ # @return [Array<String>]
94
+ def reporters
95
+ raw_data['reporters']
96
+ end
97
+
98
+ # A hash of options supported by the formatter
99
+ #
100
+ # @sg-ignore Need to validate config
101
+ # @return [Hash]
102
+ def formatter
103
+ raw_data['formatter']
104
+ end
105
+
106
+ # An array of plugins to require.
107
+ #
108
+ # @sg-ignore Need to validate config
109
+ # @return [Array<String>]
110
+ def plugins
111
+ raw_data['plugins']
112
+ end
113
+
114
+ # The maximum number of files to parse from the workspace.
115
+ #
116
+ # @sg-ignore Need to validate config
117
+ # @return [Integer]
118
+ def max_files
119
+ raw_data['max_files']
120
+ end
121
+
122
+ # @return [Hash{Symbol => Symbol}]
123
+ def type_checker_rules
124
+ # @type [Hash{String => String}]
125
+ raw_rules = raw_data.fetch('type_checker', {}).fetch('rules', {})
126
+ raw_rules.to_h do |k, v|
127
+ [k.to_sym, v.to_sym]
128
+ end
129
+ end
130
+
131
+ private
132
+
133
+ # @return [String]
134
+ def global_config_path
135
+ ENV['SOLARGRAPH_GLOBAL_CONFIG'] ||
136
+ File.join(Dir.home, '.config', 'solargraph', 'config.yml')
137
+ end
138
+
139
+ # @return [String]
140
+ def workspace_config_path
141
+ return '' if @directory.empty?
142
+ File.join(@directory, '.solargraph.yml')
143
+ end
144
+
145
+ # @return [Hash{String => undefined}]
146
+ def config_data
147
+ workspace_config = read_config(workspace_config_path)
148
+ global_config = read_config(global_config_path)
149
+
150
+ defaults = default_config
151
+ defaults.merge({ 'exclude' => [] }) unless workspace_config.nil?
152
+
153
+ defaults
154
+ .merge(global_config || {})
155
+ .merge(workspace_config || {})
156
+ end
157
+
158
+ # Read a .solargraph yaml config
159
+ #
160
+ # @param config_path [String]
161
+ # @return [Hash{String => Array, Hash, Integer}, nil]
162
+ def read_config config_path = ''
163
+ return nil if config_path.empty?
164
+ return nil unless File.file?(config_path)
165
+ YAML.safe_load_file(config_path)
166
+ end
167
+
168
+ # @return [Hash{String => Array, Hash, Integer}]
169
+ def default_config
170
+ {
171
+ 'include' => ['Rakefile', 'Gemfile', '*.gemspec', './**/*.rb'],
172
+ 'exclude' => ['spec/**/*', 'test/**/*', 'vendor/**/*', '.bundle/**/*'],
173
+ 'require' => [],
174
+ 'domains' => [],
175
+ 'reporters' => %w[rubocop require_not_found],
176
+ 'formatter' => {
177
+ 'rubocop' => {
178
+ 'cops' => 'safe',
179
+ 'except' => [],
180
+ 'only' => [],
181
+ 'extra_args' => []
182
+ }
183
+ },
184
+ 'type_checker' => {
185
+ 'rules' => {}
186
+ },
187
+ 'require_paths' => [],
188
+ 'plugins' => [],
189
+ 'max_files' => MAX_FILES
190
+ }
191
+ end
192
+
193
+ # Get an array of files from the provided globs.
194
+ #
195
+ # @param globs [Array<String>]
196
+ # @return [Array<String>]
197
+ def process_globs globs
198
+ globs.flat_map do |glob|
199
+ Dir[File.absolute_path(glob, directory)]
200
+ .map { |f| f.gsub('\\', '/') }
201
+ .select { |f| File.file?(f) }
202
+ end
203
+ end
204
+
205
+ # Modify the included files based on excluded directories and get an
206
+ # array of additional files to exclude.
207
+ #
208
+ # @param globs [Array<String>]
209
+ # @return [Array<String>]
210
+ def process_exclusions globs
211
+ remainder = globs.select do |glob|
212
+ if glob_is_directory?(glob)
213
+ exdir = File.absolute_path(glob_to_directory(glob), directory)
214
+ included.delete_if { |file| file.start_with?(exdir) }
215
+ false
216
+ else
217
+ true
218
+ end
219
+ end
220
+ process_globs remainder
221
+ end
222
+
223
+ # True if the glob translates to a whole directory.
224
+ #
225
+ # @example
226
+ # glob_is_directory?('path/to/dir') # => true
227
+ # glob_is_directory?('path/to/dir/**/*) # => true
228
+ # glob_is_directory?('path/to/file.txt') # => false
229
+ # glob_is_directory?('path/to/*.txt') # => false
230
+ #
231
+ # @param glob [String]
232
+ # @return [Boolean]
233
+ def glob_is_directory? glob
234
+ File.directory?(glob) || File.directory?(glob_to_directory(glob))
235
+ end
236
+
237
+ # Translate a glob to a base directory if applicable
238
+ #
239
+ # @example
240
+ # glob_to_directory('path/to/dir/**/*') # => 'path/to/dir'
241
+ #
242
+ # @param glob [String]
243
+ # @return [String]
244
+ def glob_to_directory glob
245
+ glob.gsub(%r{(/\*|/\*\*/\*\*?)$}, '')
246
+ end
247
+
248
+ # @return [Array<String>]
249
+ def excluded_directories
250
+ # @type [Array<String>]
251
+ excluded = @raw_data['exclude']
252
+ excluded
253
+ .select { |g| glob_is_directory?(g) }
254
+ .map { |g| File.absolute_path(glob_to_directory(g), directory) }
255
+ end
256
+ end
257
+ end
258
+ end