spoom 1.0.1 → 1.0.6

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: 79e893c05337d0cfa5dc7938fb68d6cd7736b7225d7c921ef3ca6d587fabc464
4
- data.tar.gz: d0a97f75ed01013d22718eb4286f457d3857ebee53e6ff4adda9b46fd64c48b6
3
+ metadata.gz: 8b9a6d7f3818e0af29439ba291b6c05fa29a821de374ee5c8181c64a05f3f7a3
4
+ data.tar.gz: 6d60e6fc252e6aebcfff2860778b1e2ac596740823a279aec1788ccaefa2fc4b
5
5
  SHA512:
6
- metadata.gz: 31cc4bad9b2d68d018e0c13a47cbb579c484410ac944d9202539bd62aab456fab0aee997f85c43490bf118a767c10e34e127abb41dbe0c1de8dea890df685c2d
7
- data.tar.gz: 97c334004a614cbb5118e13e0d7f6b4d98152466f699a94a1f37220bc76507ceed4a4ebe762eeb2f1cc337d5b5bcf8f2a447aedcdb3db7742f2d61be9254bc20
6
+ metadata.gz: d156b4d9c8f2edb2f68e1b5fc21b659d8bec0bc60fd9110f565889a620febce064cc3ee176228cd659f1b21ca0ab000a9790407537eb9bd18edbc41d601b963b
7
+ data.tar.gz: a7e1bf03e8bd942bc0f2ac6379739bfd795d1642025e00ef33e198b6422c61598b23c753248a698568b7c1edde23d232604b76ccdfd9d1b7ef98139c74cc583a
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  source "https://rubygems.org"
@@ -6,5 +7,7 @@ gemspec
6
7
 
7
8
  group(:development) do
8
9
  gem('rubocop-shopify', require: false)
9
- gem("tapioca", require: false)
10
+ gem('rubocop-sorbet', require: false)
11
+ gem('byebug')
12
+ gem('pry-byebug')
10
13
  end
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
@@ -1,3 +1,4 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
  require "bundler/gem_tasks"
3
4
  require "rake/testtask"
@@ -5,6 +6,7 @@ require "rake/testtask"
5
6
  Rake::TestTask.new(:test) do |t|
6
7
  t.libs << "test"
7
8
  t.libs << "lib"
9
+ t.warning = false
8
10
  t.test_files = FileList["test/**/*_test.rb"]
9
11
  end
10
12
 
data/exe/spoom CHANGED
@@ -0,0 +1,7 @@
1
+ #! /usr/bin/env ruby
2
+ # typed: true
3
+ # frozen_string_literal: true
4
+
5
+ require_relative "../lib/spoom"
6
+
7
+ Spoom::Cli::Main.start(ARGV)
@@ -1,6 +1,14 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require "sorbet-runtime"
4
5
 
6
+ module Spoom
7
+ class Error < StandardError; end
8
+ end
9
+
10
+ require "spoom/config"
11
+
12
+ require "spoom/sorbet"
13
+ require "spoom/cli"
5
14
  require "spoom/version"
6
- require "spoom/sorbet/config"
@@ -0,0 +1,68 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "thor"
5
+
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"
13
+
14
+ module Spoom
15
+ module Cli
16
+ class Main < Thor
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)
23
+
24
+ desc "bump", "bump Sorbet sigils from `false` to `true` when no errors"
25
+ subcommand "bump", Spoom::Cli::Bump
26
+
27
+ desc "config", "manage Sorbet config"
28
+ subcommand "config", Spoom::Cli::Config
29
+
30
+ desc "coverage", "collect metrics related to Sorbet coverage"
31
+ subcommand "coverage", Spoom::Cli::Coverage
32
+
33
+ desc "lsp", "send LSP requests to Sorbet"
34
+ subcommand "lsp", Spoom::Cli::LSP
35
+
36
+ desc "tc", "run Sorbet and parses its output"
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
60
+
61
+ # Utils
62
+
63
+ def self.exit_on_failure?
64
+ true
65
+ end
66
+ end
67
+ end
68
+ end
@@ -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