spoom 1.0.4 → 1.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d851bf66dbfb8e1d316b27466fde8ee205e55e68b9b489c3f8f234c03e1763d2
4
- data.tar.gz: '068972f0ebb9393400dcbf68837be0a58114cc55560438fd329be3b54acfcaaf'
3
+ metadata.gz: 7a5f19185a1beba98f75c9c96b08c06400c9917c0d85734f1dbf9c9d77e3fa74
4
+ data.tar.gz: 53f4b8b10f81b19588f58d57c93349721230836e3b98524b52c46a78f4682365
5
5
  SHA512:
6
- metadata.gz: 8315d9c7de9beaf2aa9a5d6963cde78ec6e9e7949659bac85a0ff719080755808fb5a854c2a03f6dcab8134c17bc8d90d145d53d32a3f1632d83a2c6a21ebfaa
7
- data.tar.gz: 88fee999fa79caf40dd776ce5253a1337a5acc2507653a2c09adfb3e4723b6a8a06033d34c8f299b3a7a663ef01c2fa4a8243d98fd9f104e9c77ad69f9836ff7
6
+ metadata.gz: aff5a2bc4b3bd01c815ad0d00e76fcc700728ec659135645dce259db72dc97cf8ea2d339827d979bf9f225637b7d23f2ea09d13dd02786229fe5c42caf88886e
7
+ data.tar.gz: b2760f8f58a7f3cbfd90d59e16f5bb9b76356f13fc3f38a606758652f53caf72004024128e4195451ca32f30c9d03c6bdb553a6a7aea2893c7f0e6a2e6ec2528
data/README.md CHANGED
@@ -20,7 +20,218 @@ Or install it yourself as:
20
20
 
21
21
  ## Usage
22
22
 
23
- ### Parsing Sorbet config
23
+ `spoom` provides both a CLI and an API to interact with Sorbet.
24
+
25
+ ### Generate a typing coverage report
26
+
27
+ Spoom can create a typing coverage report from Sorbet and Git data:
28
+
29
+ ![Coverage Report](docs/report.png)
30
+
31
+ After installing the `spoom` gem, run the `timeline` command to collect the history data:
32
+
33
+ ```
34
+ $ spoom coverage timeline --save
35
+ ```
36
+
37
+ Then create the HTML page with `report`:
38
+
39
+ ```
40
+ $ spoom coverage report
41
+ ```
42
+
43
+ Your report will be generated under `spoom_report.html`.
44
+
45
+ See all the [Typing Coverage](#typing-coverage) CLI commands for more details.
46
+
47
+ ### Command Line Interface
48
+
49
+ #### Sorbet configuration commands
50
+
51
+ Spoom works with your `sorbet/config` file. No additional configuration is needed.
52
+
53
+ Show Sorbet config options:
54
+
55
+ ```
56
+ $ spoom config
57
+ ```
58
+
59
+ #### Listing files
60
+
61
+ List the files (and related strictness) that will be typchecked with the current Sorbet config options:
62
+
63
+ ```
64
+ $ spoom files
65
+ ```
66
+
67
+ #### Errors sorting and filtering
68
+
69
+ List all typechecking errors sorted by location:
70
+
71
+ ```
72
+ $ spoom tc -s
73
+ ```
74
+
75
+ List all typechecking errors sorted by error code first:
76
+
77
+ ```
78
+ $ spoom tc -s code
79
+ ```
80
+
81
+ List only typechecking errors from a specific error code:
82
+
83
+ ```
84
+ $ spoom tc -c 7004
85
+ ```
86
+
87
+ List only the first 10 typechecking errors
88
+
89
+ ```
90
+ $ spoom tc -l 10
91
+ ```
92
+
93
+ These options can be combined:
94
+
95
+ ```
96
+ $ spoom tc -s -c 7004 -l 10
97
+ ```
98
+
99
+ #### Typing coverage
100
+
101
+ Show metrics about the project contents and the typing coverage:
102
+
103
+ ```
104
+ $ spoom coverage
105
+ ```
106
+
107
+ Save coverage data under `spoom_data/`:
108
+
109
+ ```
110
+ $ spoom coverage --save
111
+ ```
112
+
113
+ Save coverage data under a specific directory:
114
+
115
+ ```
116
+ $ spoom coverage --save my_data/
117
+ ```
118
+
119
+ Show typing coverage evolution based on the commits history:
120
+
121
+ ```
122
+ $ spoom coverage timeline
123
+ ```
124
+
125
+ Show typing coverage evolution based on the commits history between specific dates:
126
+
127
+ ```
128
+ $ spoom coverage timeline --from YYYY-MM-DD --to YYYY-MM-DD
129
+ ```
130
+
131
+ Save the typing coverage evolution as JSON under `spoom_data/`:
132
+
133
+ ```
134
+ $ spoom coverage timeline --save
135
+ ```
136
+
137
+ Save the typing coverage evolution as JSON in a specific directory:
138
+
139
+ ```
140
+ $ spoom coverage timeline --save my_data/
141
+ ```
142
+
143
+ Run `bundle install` for each commit of the timeline (may solve errors due to different Sorbet versions):
144
+
145
+ ```
146
+ $ spoom coverage timeline --bundle-install
147
+ ```
148
+
149
+ Generate an HTML typing coverage report:
150
+
151
+ ```
152
+ $ spoom coverage report
153
+ ```
154
+
155
+ Change the colors used for strictnesses (useful for colorblind folks):
156
+
157
+ ```
158
+ $ spoom coverage report \
159
+ --color-true "#648ffe" \
160
+ --color-false "#fe6002" \
161
+ --color-ignore "#feb000" \
162
+ --color-strict "#795ef0" \
163
+ --color-strong "#6444f1"
164
+ ```
165
+
166
+ Open the HTML typing coverage report:
167
+
168
+ ```
169
+ $ spoom coverage open
170
+ ```
171
+
172
+ #### Change the sigil used in files
173
+
174
+ Bump the strictness from all files currently at `typed: false` to `typed: true` where it does not create typechecking errors:
175
+
176
+ ```
177
+ $ spoom bump --from false --to true
178
+ ```
179
+
180
+ Bump the strictness from all files currently at `typed: false` to `typed: true` even if it creates typechecking errors:
181
+
182
+ ```
183
+ $ spoom bump --from false --to true -f
184
+ ```
185
+
186
+ #### Interact with Sorbet LSP mode
187
+
188
+ **Experimental**
189
+
190
+ Find all definitions for `Foo`:
191
+
192
+ ```
193
+ $ spoom lsp find Foo
194
+ ```
195
+
196
+ List all symbols in a file:
197
+
198
+ ```
199
+ $ spoom lsp symbols <file.rb>
200
+ ```
201
+
202
+ List all definitions for a specific code location:
203
+
204
+ ```
205
+ $ spoom lsp defs <file.rb> <line> <column>
206
+ ```
207
+
208
+ List all references for a specific code location:
209
+
210
+ ```
211
+ $ spoom lsp refs <file.rb> <line> <column>
212
+ ```
213
+
214
+ Show hover information for a specific code location:
215
+
216
+ ```
217
+ $ spoom lsp hover <file.rb> <line> <column>
218
+ ```
219
+
220
+ Show signature information for a specific code location:
221
+
222
+ ```
223
+ $ spoom lsp sig <file.rb> <line> <column>
224
+ ```
225
+
226
+ Show type information for a specific code location:
227
+
228
+ ```
229
+ $ spoom lsp sig <file.rb> <line> <column>
230
+ ```
231
+
232
+ ### API
233
+
234
+ #### Parsing Sorbet config
24
235
 
25
236
  Parses a Sorbet config file:
26
237
 
@@ -41,6 +252,47 @@ puts config.paths # "a", "b"
41
252
  puts config.ignore # "c"
42
253
  ```
43
254
 
255
+ List all files typchecked by Sorbet:
256
+
257
+ ```ruby
258
+ config = Spoom::Sorbet::Config.parse_file("sorbet/config")
259
+ puts Spoom::Sorbet.srb_files(config)
260
+ ```
261
+
262
+ #### Parsing Sorbet metrics
263
+
264
+ Display metrics collected during typechecking:
265
+
266
+ ```ruby
267
+ puts Spoom::Sorbet.srb_metrics(capture_err: false)
268
+ ```
269
+
270
+ #### Interacting with LSP
271
+
272
+ Create an LSP client:
273
+
274
+ ```rb
275
+ client = Spoom::LSP::Client.new(
276
+ Spoom::Config::SORBET_PATH,
277
+ "--lsp",
278
+ "--enable-all-experimental-lsp-features",
279
+ "--disable-watchman",
280
+ )
281
+ client.open(".")
282
+ ```
283
+
284
+ Find all the symbols matching a string:
285
+
286
+ ```rb
287
+ puts client.symbols("Foo")
288
+ ```
289
+
290
+ Find all the symbols for a file:
291
+
292
+ ```rb
293
+ puts client.document_symbols("file://path/to/my/file.rb")
294
+ ```
295
+
44
296
  ## Development
45
297
 
46
298
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. Don't forget to run `bin/sanity` before pushing your changes.
data/Rakefile CHANGED
@@ -6,6 +6,7 @@ require "rake/testtask"
6
6
  Rake::TestTask.new(:test) do |t|
7
7
  t.libs << "test"
8
8
  t.libs << "lib"
9
+ t.warning = false
9
10
  t.test_files = FileList["test/**/*_test.rb"]
10
11
  end
11
12
 
@@ -7,7 +7,8 @@ module Spoom
7
7
  class Error < StandardError; end
8
8
  end
9
9
 
10
- require "spoom/cli"
11
10
  require "spoom/config"
11
+
12
12
  require "spoom/sorbet"
13
+ require "spoom/cli"
13
14
  require "spoom/version"
@@ -3,25 +3,60 @@
3
3
 
4
4
  require "thor"
5
5
 
6
- require_relative "cli/commands/config"
7
- require_relative "cli/commands/lsp"
8
- require_relative "cli/commands/run"
6
+ require_relative 'cli/helper'
7
+
8
+ require_relative "cli/bump"
9
+ require_relative "cli/config"
10
+ require_relative "cli/lsp"
11
+ require_relative "cli/coverage"
12
+ require_relative "cli/run"
9
13
 
10
14
  module Spoom
11
15
  module Cli
12
16
  class Main < Thor
13
17
  extend T::Sig
18
+ include Helper
19
+
20
+ class_option :color, desc: "Use colors", type: :boolean, default: true
21
+ class_option :path, desc: "Run spoom in a specific path", type: :string, default: ".", aliases: :p
22
+ map T.unsafe(%w[--version -v] => :__print_version)
14
23
 
15
- class_option :no_color, desc: "Don't use colors", type: :boolean
24
+ desc "bump", "bump Sorbet sigils from `false` to `true` when no errors"
25
+ subcommand "bump", Spoom::Cli::Bump
16
26
 
17
27
  desc "config", "manage Sorbet config"
18
- subcommand "config", Spoom::Cli::Commands::Config
28
+ subcommand "config", Spoom::Cli::Config
29
+
30
+ desc "coverage", "collect metrics related to Sorbet coverage"
31
+ subcommand "coverage", Spoom::Cli::Coverage
19
32
 
20
33
  desc "lsp", "send LSP requests to Sorbet"
21
- subcommand "lsp", Spoom::Cli::Commands::LSP
34
+ subcommand "lsp", Spoom::Cli::LSP
22
35
 
23
36
  desc "tc", "run Sorbet and parses its output"
24
- subcommand "tc", Spoom::Cli::Commands::Run
37
+ subcommand "tc", Spoom::Cli::Run
38
+
39
+ desc "files", "list all the files typechecked by Sorbet"
40
+ def files
41
+ in_sorbet_project!
42
+
43
+ path = exec_path
44
+ config = Spoom::Sorbet::Config.parse_file(sorbet_config)
45
+ files = Spoom::Sorbet.srb_files(config, path: path)
46
+
47
+ say("Files matching `#{sorbet_config}`:")
48
+ if files.empty?
49
+ say(" NONE")
50
+ else
51
+ tree = FileTree.new(files, strip_prefix: path)
52
+ tree.print(colors: options[:color], indent_level: 2)
53
+ end
54
+ end
55
+
56
+ desc "--version", "show version"
57
+ def __print_version
58
+ puts "Spoom v#{Spoom::VERSION}"
59
+ end
25
60
 
26
61
  # Utils
27
62
 
@@ -0,0 +1,59 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require 'find'
5
+ require 'open3'
6
+
7
+ module Spoom
8
+ module Cli
9
+ class Bump < Thor
10
+ extend T::Sig
11
+ include Helper
12
+
13
+ default_task :bump
14
+
15
+ desc "bump DIRECTORY", "change Sorbet sigils from one strictness to another when no errors"
16
+ option :from, type: :string, default: Spoom::Sorbet::Sigils::STRICTNESS_FALSE
17
+ option :to, type: :string, default: Spoom::Sorbet::Sigils::STRICTNESS_TRUE
18
+ option :force, desc: "change strictness without type checking", type: :boolean, default: false, aliases: :f
19
+ sig { params(directory: String).void }
20
+ def bump(directory = ".")
21
+ from = options[:from]
22
+ to = options[:to]
23
+ force = options[:force]
24
+
25
+ unless Sorbet::Sigils.valid_strictness?(from)
26
+ say_error("Invalid strictness #{from} for option --from")
27
+ exit(1)
28
+ end
29
+
30
+ unless Sorbet::Sigils.valid_strictness?(to)
31
+ say_error("Invalid strictness #{to} for option --to")
32
+ exit(1)
33
+ end
34
+
35
+ files_to_bump = Sorbet::Sigils.files_with_sigil_strictness(directory, from)
36
+
37
+ Sorbet::Sigils.change_sigil_in_files(files_to_bump, to)
38
+
39
+ return [] if force
40
+
41
+ output, no_errors = Sorbet.srb_tc(path: File.expand_path(directory), capture_err: true)
42
+
43
+ return [] if no_errors
44
+
45
+ errors = Sorbet::Errors::Parser.parse_string(output)
46
+
47
+ files_with_errors = errors.map do |err|
48
+ path = err.file
49
+ File.join(directory, path) if path && File.file?(path)
50
+ end.compact.uniq
51
+
52
+ Sorbet::Sigils.change_sigil_in_files(files_with_errors, from)
53
+ end
54
+
55
+ no_commands do
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,51 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require_relative "../file_tree"
5
+ require_relative "../sorbet/config"
6
+
7
+ module Spoom
8
+ module Cli
9
+ class Config < Thor
10
+ include Helper
11
+
12
+ default_task :show
13
+
14
+ desc "show", "show Sorbet config"
15
+ def show
16
+ in_sorbet_project!
17
+ config = Spoom::Sorbet::Config.parse_file(sorbet_config)
18
+
19
+ say("Found Sorbet config at `#{sorbet_config}`.")
20
+
21
+ say("\nPaths typechecked:")
22
+ if config.paths.empty?
23
+ say(" * (default: .)")
24
+ else
25
+ config.paths.each do |path|
26
+ say(" * #{path}")
27
+ end
28
+ end
29
+
30
+ say("\nPaths ignored:")
31
+ if config.ignore.empty?
32
+ say(" * (default: none)")
33
+ else
34
+ config.ignore.each do |path|
35
+ say(" * #{path}")
36
+ end
37
+ end
38
+
39
+ say("\nAllowed extensions:")
40
+ if config.allowed_extensions.empty?
41
+ say(" * .rb (default)")
42
+ say(" * .rbi (default)")
43
+ else
44
+ config.allowed_extensions.each do |ext|
45
+ say(" * #{ext}")
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end