tapioca 0.16.9 → 0.17.7

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 (130) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +21 -0
  3. data/exe/tapioca +6 -1
  4. data/lib/ruby_lsp/tapioca/addon.rb +73 -43
  5. data/lib/ruby_lsp/tapioca/run_gem_rbi_check.rb +43 -43
  6. data/lib/ruby_lsp/tapioca/server_addon.rb +13 -10
  7. data/lib/tapioca/bundler_ext/auto_require_hook.rb +6 -14
  8. data/lib/tapioca/cli.rb +16 -8
  9. data/lib/tapioca/commands/abstract_dsl.rb +39 -66
  10. data/lib/tapioca/commands/abstract_gem.rb +25 -46
  11. data/lib/tapioca/commands/annotations.rb +28 -34
  12. data/lib/tapioca/commands/check_shims.rb +6 -15
  13. data/lib/tapioca/commands/command.rb +12 -26
  14. data/lib/tapioca/commands/command_without_tracker.rb +2 -5
  15. data/lib/tapioca/commands/configure.rb +11 -16
  16. data/lib/tapioca/commands/dsl_compiler_list.rb +2 -1
  17. data/lib/tapioca/commands/dsl_generate.rb +2 -1
  18. data/lib/tapioca/commands/dsl_verify.rb +2 -1
  19. data/lib/tapioca/commands/gem_generate.rb +5 -9
  20. data/lib/tapioca/commands/gem_sync.rb +2 -1
  21. data/lib/tapioca/commands/gem_verify.rb +3 -2
  22. data/lib/tapioca/commands/require.rb +3 -7
  23. data/lib/tapioca/commands/todo.rb +6 -10
  24. data/lib/tapioca/dsl/compiler.rb +36 -63
  25. data/lib/tapioca/dsl/compilers/aasm.rb +33 -44
  26. data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +8 -7
  27. data/lib/tapioca/dsl/compilers/action_mailer.rb +6 -5
  28. data/lib/tapioca/dsl/compilers/action_text.rb +6 -5
  29. data/lib/tapioca/dsl/compilers/active_job.rb +6 -10
  30. data/lib/tapioca/dsl/compilers/active_model_attributes.rb +10 -11
  31. data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +5 -6
  32. data/lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb +5 -12
  33. data/lib/tapioca/dsl/compilers/active_record_associations.rb +17 -44
  34. data/lib/tapioca/dsl/compilers/active_record_columns.rb +20 -26
  35. data/lib/tapioca/dsl/compilers/active_record_delegated_types.rb +9 -8
  36. data/lib/tapioca/dsl/compilers/active_record_enum.rb +7 -6
  37. data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +54 -62
  38. data/lib/tapioca/dsl/compilers/active_record_relations.rb +148 -209
  39. data/lib/tapioca/dsl/compilers/active_record_scope.rb +8 -13
  40. data/lib/tapioca/dsl/compilers/active_record_secure_token.rb +5 -4
  41. data/lib/tapioca/dsl/compilers/active_record_store.rb +5 -4
  42. data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +19 -28
  43. data/lib/tapioca/dsl/compilers/active_resource.rb +19 -21
  44. data/lib/tapioca/dsl/compilers/active_storage.rb +6 -14
  45. data/lib/tapioca/dsl/compilers/active_support_concern.rb +9 -8
  46. data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +8 -7
  47. data/lib/tapioca/dsl/compilers/active_support_time_ext.rb +5 -4
  48. data/lib/tapioca/dsl/compilers/config.rb +5 -4
  49. data/lib/tapioca/dsl/compilers/frozen_record.rb +7 -11
  50. data/lib/tapioca/dsl/compilers/graphql_input_object.rb +9 -10
  51. data/lib/tapioca/dsl/compilers/graphql_mutation.rb +6 -10
  52. data/lib/tapioca/dsl/compilers/identity_cache.rb +11 -39
  53. data/lib/tapioca/dsl/compilers/json_api_client_resource.rb +9 -18
  54. data/lib/tapioca/dsl/compilers/kredis.rb +7 -8
  55. data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +5 -4
  56. data/lib/tapioca/dsl/compilers/protobuf.rb +13 -26
  57. data/lib/tapioca/dsl/compilers/rails_generators.rb +9 -11
  58. data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +23 -13
  59. data/lib/tapioca/dsl/compilers/smart_properties.rb +32 -38
  60. data/lib/tapioca/dsl/compilers/state_machines.rb +15 -26
  61. data/lib/tapioca/dsl/compilers/url_helpers.rb +10 -9
  62. data/lib/tapioca/dsl/compilers.rb +4 -7
  63. data/lib/tapioca/dsl/helpers/active_model_type_helper.rb +13 -16
  64. data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +13 -28
  65. data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +19 -15
  66. data/lib/tapioca/dsl/helpers/graphql_type_helper.rb +5 -24
  67. data/lib/tapioca/dsl/pipeline.rb +30 -58
  68. data/lib/tapioca/executor.rb +6 -12
  69. data/lib/tapioca/gem/events.rb +24 -34
  70. data/lib/tapioca/gem/listeners/base.rb +7 -10
  71. data/lib/tapioca/gem/listeners/dynamic_mixins.rb +4 -2
  72. data/lib/tapioca/gem/listeners/foreign_constants.rb +5 -7
  73. data/lib/tapioca/gem/listeners/methods.rb +36 -47
  74. data/lib/tapioca/gem/listeners/mixins.rb +6 -18
  75. data/lib/tapioca/gem/listeners/remove_empty_payload_scopes.rb +4 -2
  76. data/lib/tapioca/gem/listeners/sorbet_enums.rb +4 -2
  77. data/lib/tapioca/gem/listeners/sorbet_helpers.rb +4 -2
  78. data/lib/tapioca/gem/listeners/sorbet_props.rb +4 -2
  79. data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +4 -2
  80. data/lib/tapioca/gem/listeners/sorbet_signatures.rb +7 -5
  81. data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +6 -4
  82. data/lib/tapioca/gem/listeners/source_location.rb +15 -8
  83. data/lib/tapioca/gem/listeners/subconstants.rb +5 -4
  84. data/lib/tapioca/gem/listeners/yard_doc.rb +30 -23
  85. data/lib/tapioca/gem/pipeline.rb +107 -91
  86. data/lib/tapioca/gem_info.rb +1 -1
  87. data/lib/tapioca/gemfile.rb +64 -73
  88. data/lib/tapioca/helpers/cli_helper.rb +4 -7
  89. data/lib/tapioca/helpers/config_helper.rb +17 -29
  90. data/lib/tapioca/helpers/env_helper.rb +2 -5
  91. data/lib/tapioca/helpers/gem_helper.rb +5 -5
  92. data/lib/tapioca/helpers/git_attributes.rb +3 -3
  93. data/lib/tapioca/helpers/rbi_files_helper.rb +76 -73
  94. data/lib/tapioca/helpers/rbi_helper.rb +14 -22
  95. data/lib/tapioca/helpers/sorbet_helper.rb +9 -18
  96. data/lib/tapioca/helpers/source_uri.rb +15 -25
  97. data/lib/tapioca/helpers/test/content.rb +7 -10
  98. data/lib/tapioca/helpers/test/dsl_compiler.rb +20 -33
  99. data/lib/tapioca/helpers/test/isolation.rb +10 -14
  100. data/lib/tapioca/helpers/test/template.rb +6 -11
  101. data/lib/tapioca/internal.rb +18 -8
  102. data/lib/tapioca/loaders/dsl.rb +11 -19
  103. data/lib/tapioca/loaders/gem.rb +6 -21
  104. data/lib/tapioca/loaders/loader.rb +21 -39
  105. data/lib/tapioca/rbi_ext/model.rb +12 -37
  106. data/lib/tapioca/rbi_formatter.rb +10 -19
  107. data/lib/tapioca/rbs/rewriter.rb +55 -0
  108. data/lib/tapioca/repo_index.rb +7 -9
  109. data/lib/tapioca/runtime/attached_class_of_32.rb +1 -1
  110. data/lib/tapioca/runtime/attached_class_of_legacy.rb +2 -5
  111. data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +23 -23
  112. data/lib/tapioca/runtime/generic_type_registry.rb +13 -23
  113. data/lib/tapioca/runtime/reflection.rb +81 -60
  114. data/lib/tapioca/runtime/source_location.rb +44 -0
  115. data/lib/tapioca/runtime/trackers/autoload.rb +7 -9
  116. data/lib/tapioca/runtime/trackers/constant_definition.rb +18 -14
  117. data/lib/tapioca/runtime/trackers/method_definition.rb +65 -0
  118. data/lib/tapioca/runtime/trackers/mixin.rb +8 -11
  119. data/lib/tapioca/runtime/trackers/required_ancestor.rb +3 -3
  120. data/lib/tapioca/runtime/trackers/tracker.rb +3 -6
  121. data/lib/tapioca/runtime/trackers.rb +5 -8
  122. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +9 -15
  123. data/lib/tapioca/sorbet_ext/name_patch.rb +2 -2
  124. data/lib/tapioca/sorbet_ext/proc_bind_patch.rb +1 -1
  125. data/lib/tapioca/static/requires_compiler.rb +6 -6
  126. data/lib/tapioca/static/symbol_loader.rb +14 -16
  127. data/lib/tapioca/static/symbol_table_parser.rb +8 -8
  128. data/lib/tapioca/version.rb +1 -1
  129. data/lib/tapioca.rb +22 -29
  130. metadata +27 -10
@@ -3,34 +3,12 @@
3
3
 
4
4
  module Tapioca
5
5
  module Commands
6
+ # @abstract
6
7
  class AbstractDsl < CommandWithoutTracker
7
8
  include SorbetHelper
8
9
  include RBIFilesHelper
9
10
 
10
- abstract!
11
-
12
- sig do
13
- params(
14
- requested_constants: T::Array[String],
15
- requested_paths: T::Array[Pathname],
16
- outpath: Pathname,
17
- only: T::Array[String],
18
- exclude: T::Array[String],
19
- file_header: T::Boolean,
20
- tapioca_path: String,
21
- skip_constant: T::Array[String],
22
- quiet: T::Boolean,
23
- verbose: T::Boolean,
24
- number_of_workers: T.nilable(Integer),
25
- auto_strictness: T::Boolean,
26
- gem_dir: String,
27
- rbi_formatter: RBIFormatter,
28
- app_root: String,
29
- halt_upon_load_error: T::Boolean,
30
- compiler_options: T::Hash[String, T.untyped],
31
- lsp_addon: T::Boolean,
32
- ).void
33
- end
11
+ #: (requested_constants: Array[String], requested_paths: Array[Pathname], outpath: Pathname, only: Array[String], exclude: Array[String], file_header: bool, tapioca_path: String, ?skip_constant: Array[String], ?quiet: bool, ?verbose: bool, ?number_of_workers: Integer?, ?auto_strictness: bool, ?gem_dir: String, ?rbi_formatter: RBIFormatter, ?app_root: String, ?halt_upon_load_error: bool, ?compiler_options: Hash[String, untyped], ?lsp_addon: bool) -> void
34
12
  def initialize(
35
13
  requested_constants:,
36
14
  requested_paths:,
@@ -75,7 +53,7 @@ module Tapioca
75
53
 
76
54
  private
77
55
 
78
- sig { params(outpath: Pathname, quiet: T::Boolean).returns(T::Set[Pathname]) }
56
+ #: (Pathname outpath, quiet: bool) -> Set[Pathname]
79
57
  def generate_dsl_rbi_files(outpath, quiet:)
80
58
  if @lsp_addon
81
59
  pipeline.active_compilers.each(&:reset_state)
@@ -103,20 +81,17 @@ module Tapioca
103
81
  files_to_purge
104
82
  end
105
83
 
106
- sig { returns(T::Array[String]) }
84
+ #: -> Array[String]
107
85
  def all_requested_constants
108
- @all_requested_constants ||= T.let(
109
- @requested_constants + constants_from_requested_paths,
110
- T.nilable(T::Array[String]),
111
- )
86
+ @all_requested_constants ||= @requested_constants + constants_from_requested_paths #: Array[String]?
112
87
  end
113
88
 
114
- sig { returns(Tapioca::Dsl::Pipeline) }
89
+ #: -> Tapioca::Dsl::Pipeline
115
90
  def pipeline
116
- @pipeline ||= T.let(create_pipeline, T.nilable(Tapioca::Dsl::Pipeline))
91
+ @pipeline ||= create_pipeline #: Tapioca::Dsl::Pipeline?
117
92
  end
118
93
 
119
- sig { void }
94
+ #: -> void
120
95
  def load_application
121
96
  # Loaded ahead of time when using the add-on to avoid reloading multiple times
122
97
  return if @lsp_addon
@@ -129,17 +104,24 @@ module Tapioca
129
104
  )
130
105
  end
131
106
 
132
- sig { returns(Tapioca::Dsl::Pipeline) }
107
+ #: -> Tapioca::Dsl::Pipeline
133
108
  def create_pipeline
109
+ error_handler = if @lsp_addon
110
+ ->(error) {
111
+ say(error)
112
+ }
113
+ else
114
+ ->(error) {
115
+ say_error(error, :bold, :red)
116
+ }
117
+ end
134
118
  Tapioca::Dsl::Pipeline.new(
135
119
  requested_constants:
136
120
  constantize(@requested_constants) + constantize(constants_from_requested_paths, ignore_missing: true),
137
121
  requested_paths: @requested_paths,
138
122
  requested_compilers: constantize_compilers(@only),
139
123
  excluded_compilers: constantize_compilers(@exclude),
140
- error_handler: ->(error) {
141
- say_error(error, :bold, :red)
142
- },
124
+ error_handler: error_handler,
143
125
  skipped_constants: constantize(@skip_constant, ignore_missing: true),
144
126
  number_of_workers: @number_of_workers,
145
127
  compiler_options: @compiler_options,
@@ -147,7 +129,7 @@ module Tapioca
147
129
  )
148
130
  end
149
131
 
150
- sig { params(requested_constants: T::Array[String], path: Pathname).returns(T::Set[Pathname]) }
132
+ #: (Array[String] requested_constants, ?path: Pathname) -> Set[Pathname]
151
133
  def existing_rbi_filenames(requested_constants, path: @outpath)
152
134
  filenames = if requested_constants.empty?
153
135
  Pathname.glob(path / "**/*.rbi")
@@ -161,7 +143,7 @@ module Tapioca
161
143
  filenames.to_set
162
144
  end
163
145
 
164
- sig { params(constant_names: T::Array[String], ignore_missing: T::Boolean).returns(T::Array[Module]) }
146
+ #: (Array[String] constant_names, ?ignore_missing: bool) -> Array[Module]
165
147
  def constantize(constant_names, ignore_missing: false)
166
148
  constant_map = constant_names.to_h do |name|
167
149
  [name, Object.const_get(name)]
@@ -178,7 +160,7 @@ module Tapioca
178
160
  remove_file(filename) if File.file?(filename)
179
161
  end
180
162
 
181
- raise Thor::Error, ""
163
+ raise Tapioca::Error, ""
182
164
  end
183
165
 
184
166
  processable_constants
@@ -186,7 +168,7 @@ module Tapioca
186
168
  .grep(Module)
187
169
  end
188
170
 
189
- sig { params(compiler_names: T::Array[String]).returns(T::Array[T.class_of(Tapioca::Dsl::Compiler)]) }
171
+ #: (Array[String] compiler_names) -> Array[singleton(Tapioca::Dsl::Compiler)]
190
172
  def constantize_compilers(compiler_names)
191
173
  compiler_map = compiler_names.to_h do |name|
192
174
  [name, resolve(name)]
@@ -206,7 +188,7 @@ module Tapioca
206
188
  T.cast(compiler_map.values, T::Array[T.class_of(Tapioca::Dsl::Compiler)])
207
189
  end
208
190
 
209
- sig { params(name: String).returns(T.nilable(T.class_of(Tapioca::Dsl::Compiler))) }
191
+ #: (String name) -> singleton(Tapioca::Dsl::Compiler)?
210
192
  def resolve(name)
211
193
  # Try to find built-in tapioca compiler first, then globally defined compiler.
212
194
  potentials = Tapioca::Dsl::Compilers::NAMESPACES.map do |namespace|
@@ -219,14 +201,7 @@ module Tapioca
219
201
  potentials.compact.first
220
202
  end
221
203
 
222
- sig do
223
- params(
224
- constant_name: String,
225
- rbi: RBI::File,
226
- outpath: Pathname,
227
- quiet: T::Boolean,
228
- ).returns(T.nilable(Pathname))
229
- end
204
+ #: (String constant_name, RBI::File rbi, ?outpath: Pathname, ?quiet: bool) -> Pathname?
230
205
  def compile_dsl_rbi(constant_name, rbi, outpath: @outpath, quiet: false)
231
206
  return if rbi.empty?
232
207
 
@@ -244,7 +219,7 @@ module Tapioca
244
219
  filename
245
220
  end
246
221
 
247
- sig { params(dir: Pathname).void }
222
+ #: (Pathname dir) -> void
248
223
  def perform_dsl_verification(dir)
249
224
  diff = verify_dsl_rbi(tmp_dir: dir)
250
225
 
@@ -253,7 +228,7 @@ module Tapioca
253
228
  FileUtils.remove_entry(dir)
254
229
  end
255
230
 
256
- sig { params(files: T::Set[Pathname]).void }
231
+ #: (Set[Pathname] files) -> void
257
232
  def purge_stale_dsl_rbi_files(files)
258
233
  if files.any?
259
234
  say("Removing stale RBI files...")
@@ -265,12 +240,12 @@ module Tapioca
265
240
  end
266
241
  end
267
242
 
268
- sig { params(constant_name: String).returns(Pathname) }
243
+ #: (String constant_name) -> Pathname
269
244
  def dsl_rbi_filename(constant_name)
270
245
  @outpath / "#{underscore(constant_name)}.rbi"
271
246
  end
272
247
 
273
- sig { params(tmp_dir: Pathname).returns(T::Hash[String, Symbol]) }
248
+ #: (tmp_dir: Pathname) -> Hash[String, Symbol]
274
249
  def verify_dsl_rbi(tmp_dir:)
275
250
  diff = {}
276
251
 
@@ -302,7 +277,7 @@ module Tapioca
302
277
  diff
303
278
  end
304
279
 
305
- sig { params(cause: Symbol, files: T::Array[String]).returns(String) }
280
+ #: (Symbol cause, Array[String] files) -> String
306
281
  def build_error_for_files(cause, files)
307
282
  filenames = files.map do |file|
308
283
  @outpath / file
@@ -311,7 +286,7 @@ module Tapioca
311
286
  " File(s) #{cause}:\n - #{filenames}"
312
287
  end
313
288
 
314
- sig { params(diff: T::Hash[String, Symbol], command: Symbol).void }
289
+ #: (Hash[String, Symbol] diff, Symbol command) -> void
315
290
  def report_diff_and_exit_if_out_of_date(diff, command)
316
291
  if diff.empty?
317
292
  say("Nothing to do, all RBIs are up-to-date.")
@@ -320,7 +295,7 @@ module Tapioca
320
295
  build_error_for_files(cause, diff_for_cause.map(&:first))
321
296
  end.join("\n")
322
297
 
323
- raise Thor::Error, <<~ERROR
298
+ raise Tapioca::Error, <<~ERROR
324
299
  #{set_color("RBI files are out-of-date. In your development environment, please run:", :green)}
325
300
  #{set_color("`#{default_command(command)}`", :green, :bold)}
326
301
  #{set_color("Once it is complete, be sure to commit and push any changes", :green)}
@@ -333,14 +308,14 @@ module Tapioca
333
308
  end
334
309
  end
335
310
 
336
- sig { params(path: Pathname).returns(T::Array[Pathname]) }
311
+ #: (Pathname path) -> Array[Pathname]
337
312
  def rbi_files_in(path)
338
313
  Pathname.glob(path / "**/*.rbi").map do |file|
339
314
  file.relative_path_from(path)
340
315
  end.sort
341
316
  end
342
317
 
343
- sig { params(class_name: String).returns(String) }
318
+ #: (String class_name) -> String
344
319
  def underscore(class_name)
345
320
  return class_name unless /[A-Z-]|::/.match?(class_name)
346
321
 
@@ -352,22 +327,20 @@ module Tapioca
352
327
  word
353
328
  end
354
329
 
355
- sig { params(constant: String).returns(String) }
330
+ #: (String constant) -> String
356
331
  def rbi_filename_for(constant)
357
332
  underscore(constant) + ".rbi"
358
333
  end
359
334
 
360
- sig { params(constant: String).returns(String) }
335
+ #: (String constant) -> String
361
336
  def generate_command_for(constant)
362
337
  default_command(:dsl, constant)
363
338
  end
364
339
 
365
- sig { returns(T::Array[String]) }
340
+ #: -> Array[String]
366
341
  def constants_from_requested_paths
367
- @constants_from_requested_paths ||= T.let(
368
- Static::SymbolLoader.symbols_from_paths(@requested_paths).to_a,
369
- T.nilable(T::Array[String]),
370
- )
342
+ @constants_from_requested_paths ||=
343
+ Static::SymbolLoader.symbols_from_paths(@requested_paths).to_a #: Array[String]?
371
344
  end
372
345
  end
373
346
  end
@@ -3,33 +3,12 @@
3
3
 
4
4
  module Tapioca
5
5
  module Commands
6
+ # @abstract
6
7
  class AbstractGem < Command
7
8
  include SorbetHelper
8
9
  include RBIFilesHelper
9
10
 
10
- abstract!
11
-
12
- sig do
13
- params(
14
- gem_names: T::Array[String],
15
- exclude: T::Array[String],
16
- include_dependencies: T::Boolean,
17
- prerequire: T.nilable(String),
18
- postrequire: String,
19
- typed_overrides: T::Hash[String, String],
20
- outpath: Pathname,
21
- file_header: T::Boolean,
22
- include_doc: T::Boolean,
23
- include_loc: T::Boolean,
24
- include_exported_rbis: T::Boolean,
25
- number_of_workers: T.nilable(Integer),
26
- auto_strictness: T::Boolean,
27
- dsl_dir: String,
28
- rbi_formatter: RBIFormatter,
29
- halt_upon_load_error: T::Boolean,
30
- lsp_addon: T.nilable(T::Boolean),
31
- ).void
32
- end
11
+ #: (gem_names: Array[String], exclude: Array[String], include_dependencies: bool, prerequire: String?, postrequire: String, typed_overrides: Hash[String, String], outpath: Pathname, file_header: bool, include_doc: bool, include_loc: bool, include_exported_rbis: bool, ?number_of_workers: Integer?, ?auto_strictness: bool, ?dsl_dir: String, ?rbi_formatter: RBIFormatter, ?halt_upon_load_error: bool, ?lsp_addon: bool?) -> void
33
12
  def initialize(
34
13
  gem_names:,
35
14
  exclude:,
@@ -65,18 +44,18 @@ module Tapioca
65
44
 
66
45
  super()
67
46
 
68
- @bundle = T.let(Gemfile.new(exclude), Gemfile)
69
- @existing_rbis = T.let(nil, T.nilable(T::Hash[String, String]))
70
- @expected_rbis = T.let(nil, T.nilable(T::Hash[String, String]))
71
- @include_doc = T.let(include_doc, T::Boolean)
72
- @include_loc = T.let(include_loc, T::Boolean)
47
+ @bundle = Gemfile.new(exclude) #: Gemfile
48
+ @existing_rbis = nil #: Hash[String, String]?
49
+ @expected_rbis = nil #: Hash[String, String]?
50
+ @include_doc = include_doc #: bool
51
+ @include_loc = include_loc #: bool
73
52
  @include_exported_rbis = include_exported_rbis
74
53
  @halt_upon_load_error = halt_upon_load_error
75
54
  end
76
55
 
77
56
  private
78
57
 
79
- sig { params(gem: Gemfile::GemSpec).void }
58
+ #: (Gemfile::GemSpec gem) -> void
80
59
  def compile_gem_rbi(gem)
81
60
  gem_name = set_color(gem.name, :yellow, :bold)
82
61
 
@@ -116,12 +95,12 @@ module Tapioca
116
95
  end
117
96
  end
118
97
 
119
- sig { void }
98
+ #: -> void
120
99
  def perform_removals
121
100
  say("Removing RBI files of gems that have been removed:", [:blue, :bold])
122
101
  puts
123
102
 
124
- anything_done = T.let(false, T::Boolean)
103
+ anything_done = false #: bool
125
104
 
126
105
  gems = removed_rbis
127
106
 
@@ -143,12 +122,12 @@ module Tapioca
143
122
  anything_done
144
123
  end
145
124
 
146
- sig { void }
125
+ #: -> void
147
126
  def perform_additions
148
127
  say("Generating RBI files of gems that are added or updated:", [:blue, :bold])
149
128
  puts
150
129
 
151
- anything_done = T.let(false, T::Boolean)
130
+ anything_done = false #: bool
152
131
 
153
132
  gems = added_rbis
154
133
 
@@ -186,34 +165,34 @@ module Tapioca
186
165
  anything_done
187
166
  end
188
167
 
189
- sig { returns(T::Array[String]) }
168
+ #: -> Array[String]
190
169
  def removed_rbis
191
170
  (existing_rbis.keys - expected_rbis.keys).sort
192
171
  end
193
172
 
194
- sig { params(gem_name: String).returns(Pathname) }
173
+ #: (String gem_name) -> Pathname
195
174
  def existing_rbi(gem_name)
196
175
  gem_rbi_filename(gem_name, T.must(existing_rbis[gem_name]))
197
176
  end
198
177
 
199
- sig { returns(T::Array[String]) }
178
+ #: -> Array[String]
200
179
  def added_rbis
201
180
  expected_rbis.select do |name, value|
202
181
  existing_rbis[name] != value
203
182
  end.keys.sort
204
183
  end
205
184
 
206
- sig { params(gem_name: String).returns(Pathname) }
185
+ #: (String gem_name) -> Pathname
207
186
  def expected_rbi(gem_name)
208
187
  gem_rbi_filename(gem_name, T.must(expected_rbis[gem_name]))
209
188
  end
210
189
 
211
- sig { params(gem_name: String).returns(T::Boolean) }
190
+ #: (String gem_name) -> bool
212
191
  def gem_rbi_exists?(gem_name)
213
192
  existing_rbis.key?(gem_name)
214
193
  end
215
194
 
216
- sig { params(diff: T::Hash[String, Symbol], command: Symbol).void }
195
+ #: (Hash[String, Symbol] diff, Symbol command) -> void
217
196
  def report_diff_and_exit_if_out_of_date(diff, command)
218
197
  if diff.empty?
219
198
  say("Nothing to do, all RBIs are up-to-date.")
@@ -222,7 +201,7 @@ module Tapioca
222
201
  build_error_for_files(cause, diff_for_cause.map(&:first))
223
202
  end.join("\n")
224
203
 
225
- raise Thor::Error, <<~ERROR
204
+ raise Tapioca::Error, <<~ERROR
226
205
  #{set_color("RBI files are out-of-date. In your development environment, please run:", :green)}
227
206
  #{set_color("`#{default_command(command)}`", :green, :bold)}
228
207
  #{set_color("Once it is complete, be sure to commit and push any changes", :green)}
@@ -233,36 +212,36 @@ module Tapioca
233
212
  end
234
213
  end
235
214
 
236
- sig { params(old_filename: Pathname, new_filename: Pathname).void }
215
+ #: (Pathname old_filename, Pathname new_filename) -> void
237
216
  def move(old_filename, new_filename)
238
217
  say("-> Moving: #{old_filename} to #{new_filename}")
239
218
  old_filename.rename(new_filename.to_s)
240
219
  end
241
220
 
242
- sig { returns(T::Hash[String, String]) }
221
+ #: -> Hash[String, String]
243
222
  def existing_rbis
244
223
  @existing_rbis ||= Pathname.glob((@outpath / "*@*.rbi").to_s)
245
224
  .to_h { |f| T.cast(f.basename(".*").to_s.split("@", 2), [String, String]) }
246
225
  end
247
226
 
248
- sig { returns(T::Hash[String, String]) }
227
+ #: -> Hash[String, String]
249
228
  def expected_rbis
250
229
  @expected_rbis ||= @bundle.dependencies
251
230
  .reject { |gem| @exclude.include?(gem.name) }
252
231
  .to_h { |gem| [gem.name, gem.version.to_s] }
253
232
  end
254
233
 
255
- sig { params(gem_name: String, version: String).returns(Pathname) }
234
+ #: (String gem_name, String version) -> Pathname
256
235
  def gem_rbi_filename(gem_name, version)
257
236
  @outpath / "#{gem_name}@#{version}.rbi"
258
237
  end
259
238
 
260
- sig { params(cause: Symbol, files: T::Array[String]).returns(String) }
239
+ #: (Symbol cause, Array[String] files) -> String
261
240
  def build_error_for_files(cause, files)
262
241
  " File(s) #{cause}:\n - #{files.join("\n - ")}"
263
242
  end
264
243
 
265
- sig { params(gem: Gemfile::GemSpec, file: RBI::File).void }
244
+ #: (Gemfile::GemSpec gem, RBI::File file) -> void
266
245
  def merge_with_exported_rbi(gem, file)
267
246
  return file unless gem.export_rbi_files?
268
247
 
@@ -6,15 +6,7 @@ module Tapioca
6
6
  class Annotations < CommandWithoutTracker
7
7
  extend T::Sig
8
8
 
9
- sig do
10
- params(
11
- central_repo_root_uris: T::Array[String],
12
- auth: T.nilable(String),
13
- netrc_file: T.nilable(String),
14
- central_repo_index_path: String,
15
- typed_overrides: T::Hash[String, String],
16
- ).void
17
- end
9
+ #: (central_repo_root_uris: Array[String], ?auth: String?, ?netrc_file: String?, ?central_repo_index_path: String, ?typed_overrides: Hash[String, String]) -> void
18
10
  def initialize(
19
11
  central_repo_root_uris:,
20
12
  auth: nil,
@@ -23,19 +15,20 @@ module Tapioca
23
15
  typed_overrides: {}
24
16
  )
25
17
  super()
26
- @outpath = T.let(Pathname.new(DEFAULT_ANNOTATIONS_DIR), Pathname)
18
+ @outpath = Pathname.new(DEFAULT_ANNOTATIONS_DIR) #: Pathname
27
19
  @central_repo_root_uris = central_repo_root_uris
28
20
  @auth = auth
29
21
  @netrc_file = netrc_file
30
- @netrc_info = T.let(nil, T.nilable(Netrc))
31
- @tokens = T.let(repo_tokens, T::Hash[String, T.nilable(String)])
32
- @indexes = T.let({}, T::Hash[String, RepoIndex])
22
+ @netrc_info = nil #: Netrc?
23
+ @tokens = repo_tokens #: Hash[String, String?]
24
+ @indexes = {} #: Hash[String, RepoIndex]
33
25
  @typed_overrides = typed_overrides
34
26
  end
35
27
 
36
28
  private
37
29
 
38
- sig { override.void }
30
+ # @override
31
+ #: -> void
39
32
  def execute
40
33
  @indexes = fetch_indexes
41
34
  project_gems = list_gemfile_gems
@@ -46,7 +39,7 @@ module Tapioca
46
39
  GitAttributes.create_vendored_attribute_file(@outpath)
47
40
  end
48
41
 
49
- sig { returns(T::Array[GemInfo]) }
42
+ #: -> Array[GemInfo]
50
43
  def list_gemfile_gems
51
44
  say("Listing gems from Gemfile.lock... ", [:blue, :bold])
52
45
  gemfile = Bundler.read_file("Gemfile.lock")
@@ -56,7 +49,7 @@ module Tapioca
56
49
  gem_info
57
50
  end
58
51
 
59
- sig { params(project_gems: T::Array[GemInfo]).void }
52
+ #: (Array[GemInfo] project_gems) -> void
60
53
  def remove_expired_annotations(project_gems)
61
54
  say("Removing annotations for gems that have been removed... ", [:blue, :bold])
62
55
 
@@ -77,11 +70,11 @@ module Tapioca
77
70
  say("\nDone\n\n", :green)
78
71
  end
79
72
 
80
- sig { returns(T::Hash[String, RepoIndex]) }
73
+ #: -> Hash[String, RepoIndex]
81
74
  def fetch_indexes
82
75
  multiple_repos = @central_repo_root_uris.size > 1
83
76
  repo_number = 1
84
- indexes = T.let({}, T::Hash[String, RepoIndex])
77
+ indexes = {} #: Hash[String, RepoIndex]
85
78
 
86
79
  @central_repo_root_uris.each do |uri|
87
80
  index = fetch_index(uri, repo_number: multiple_repos ? repo_number : nil)
@@ -92,13 +85,13 @@ module Tapioca
92
85
  end
93
86
 
94
87
  if indexes.empty?
95
- raise Thor::Error, set_color("Can't fetch annotations without sources (no index fetched)", :bold, :red)
88
+ raise Tapioca::Error, set_color("Can't fetch annotations without sources (no index fetched)", :bold, :red)
96
89
  end
97
90
 
98
91
  indexes
99
92
  end
100
93
 
101
- sig { params(repo_uri: String, repo_number: T.nilable(Integer)).returns(T.nilable(RepoIndex)) }
94
+ #: (String repo_uri, repo_number: Integer?) -> RepoIndex?
102
95
  def fetch_index(repo_uri, repo_number:)
103
96
  say("Retrieving index from central repository#{repo_number ? " ##{repo_number}" : ""}... ", [:blue, :bold])
104
97
  content = fetch_file(repo_uri, CENTRAL_REPO_INDEX_PATH)
@@ -109,10 +102,10 @@ module Tapioca
109
102
  index
110
103
  end
111
104
 
112
- sig { params(project_gems: T::Array[GemInfo]).returns(T::Array[String]) }
105
+ #: (Array[GemInfo] project_gems) -> Array[String]
113
106
  def fetch_annotations(project_gems)
114
107
  say("Fetching gem annotations from central repository... ", [:blue, :bold])
115
- fetchable_gems = T.let(Hash.new { |h, k| h[k] = [] }, T::Hash[GemInfo, T::Array[String]])
108
+ fetchable_gems = Hash.new { |h, k| h[k] = [] } #: Hash[GemInfo, Array[String]]
116
109
 
117
110
  project_gems.each_with_object(fetchable_gems) do |gem_info, hash|
118
111
  @indexes.each do |uri, index|
@@ -132,7 +125,7 @@ module Tapioca
132
125
  fetched_gems.keys.map(&:name).sort
133
126
  end
134
127
 
135
- sig { params(repo_uris: T::Array[String], gem_info: GemInfo).void }
128
+ #: (Array[String] repo_uris, GemInfo gem_info) -> bool
136
129
  def fetch_annotation(repo_uris, gem_info)
137
130
  gem_name = gem_info.name
138
131
  gem_version = gem_info.version
@@ -142,7 +135,7 @@ module Tapioca
142
135
  end
143
136
 
144
137
  content = merge_files(gem_name, contents.compact)
145
- return unless content
138
+ return false unless content
146
139
 
147
140
  content = apply_typed_override(gem_name, content)
148
141
  content = filter_versions(gem_version, content)
@@ -150,9 +143,10 @@ module Tapioca
150
143
 
151
144
  say("\n Fetched #{set_color(gem_name, :yellow, :bold)}", :green)
152
145
  create_file(@outpath.join("#{gem_name}.rbi"), content)
146
+ true
153
147
  end
154
148
 
155
- sig { params(repo_uri: String, path: String).returns(T.nilable(String)) }
149
+ #: (String repo_uri, String path) -> String?
156
150
  def fetch_file(repo_uri, path)
157
151
  if repo_uri.start_with?(%r{https?://})
158
152
  fetch_http_file(repo_uri, path)
@@ -161,7 +155,7 @@ module Tapioca
161
155
  end
162
156
  end
163
157
 
164
- sig { params(repo_uri: String, path: String).returns(T.nilable(String)) }
158
+ #: (String repo_uri, String path) -> String?
165
159
  def fetch_local_file(repo_uri, path)
166
160
  File.read("#{repo_uri}/#{path}")
167
161
  rescue => e
@@ -169,7 +163,7 @@ module Tapioca
169
163
  nil
170
164
  end
171
165
 
172
- sig { params(repo_uri: String, path: String).returns(T.nilable(String)) }
166
+ #: (String repo_uri, String path) -> String?
173
167
  def fetch_http_file(repo_uri, path)
174
168
  auth = @tokens[repo_uri]
175
169
  uri = URI("#{repo_uri}/#{path}")
@@ -193,7 +187,7 @@ module Tapioca
193
187
  nil
194
188
  end
195
189
 
196
- sig { params(name: String, content: String).returns(String) }
190
+ #: (String name, String content) -> String
197
191
  def add_header(name, content)
198
192
  # WARNING: Changing this header could impact how GitHub determines if the file should be hidden:
199
193
  # https://github.com/github/linguist/pull/6143
@@ -213,7 +207,7 @@ module Tapioca
213
207
  end
214
208
  end
215
209
 
216
- sig { params(name: String, content: String).returns(String) }
210
+ #: (String name, String content) -> String
217
211
  def apply_typed_override(name, content)
218
212
  strictness = @typed_overrides[name]
219
213
  return content unless strictness
@@ -225,7 +219,7 @@ module Tapioca
225
219
  Spoom::Sorbet::Sigils.update_sigil(content, strictness)
226
220
  end
227
221
 
228
- sig { params(gem_version: ::Gem::Version, content: String).returns(String) }
222
+ #: (::Gem::Version gem_version, String content) -> String
229
223
  def filter_versions(gem_version, content)
230
224
  rbi = RBI::Parser.parse_string(content)
231
225
  rbi.filter_versions!(gem_version)
@@ -233,7 +227,7 @@ module Tapioca
233
227
  rbi.string
234
228
  end
235
229
 
236
- sig { params(gem_name: String, contents: T::Array[String]).returns(T.nilable(String)) }
230
+ #: (String gem_name, Array[String] contents) -> String?
237
231
  def merge_files(gem_name, contents)
238
232
  return if contents.empty?
239
233
 
@@ -260,7 +254,7 @@ module Tapioca
260
254
  nil
261
255
  end
262
256
 
263
- sig { returns(T::Hash[String, T.nilable(String)]) }
257
+ #: -> Hash[String, String?]
264
258
  def repo_tokens
265
259
  @netrc_info = Netrc.read(@netrc_file) if @netrc_file
266
260
  @central_repo_root_uris.filter_map do |uri|
@@ -272,7 +266,7 @@ module Tapioca
272
266
  end.to_h
273
267
  end
274
268
 
275
- sig { params(repo_uri: String).returns(T.nilable(String)) }
269
+ #: (String repo_uri) -> String?
276
270
  def token_for(repo_uri)
277
271
  return unless @netrc_info
278
272
 
@@ -288,7 +282,7 @@ module Tapioca
288
282
  "token #{token}"
289
283
  end
290
284
 
291
- sig { params(path: String, repo_uri: String, message: String).void }
285
+ #: (String path, String repo_uri, message: String) -> void
292
286
  def say_http_error(path, repo_uri, message:)
293
287
  say_error("\nCan't fetch file `#{path}` from #{repo_uri} (#{message})\n\n", :bold, :red)
294
288
  say_error(<<~ERROR)