tapioca 0.4.27 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +15 -15
  3. data/README.md +2 -2
  4. data/Rakefile +5 -7
  5. data/exe/tapioca +2 -2
  6. data/lib/tapioca/cli.rb +172 -2
  7. data/lib/tapioca/compilers/dsl/aasm.rb +122 -0
  8. data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +52 -12
  9. data/lib/tapioca/compilers/dsl/action_mailer.rb +6 -9
  10. data/lib/tapioca/compilers/dsl/active_job.rb +8 -12
  11. data/lib/tapioca/compilers/dsl/active_model_attributes.rb +131 -0
  12. data/lib/tapioca/compilers/dsl/active_model_secure_password.rb +101 -0
  13. data/lib/tapioca/compilers/dsl/active_record_associations.rb +33 -54
  14. data/lib/tapioca/compilers/dsl/active_record_columns.rb +10 -105
  15. data/lib/tapioca/compilers/dsl/active_record_enum.rb +8 -10
  16. data/lib/tapioca/compilers/dsl/active_record_fixtures.rb +86 -0
  17. data/lib/tapioca/compilers/dsl/active_record_scope.rb +7 -10
  18. data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +5 -8
  19. data/lib/tapioca/compilers/dsl/active_resource.rb +9 -37
  20. data/lib/tapioca/compilers/dsl/active_storage.rb +98 -0
  21. data/lib/tapioca/compilers/dsl/active_support_concern.rb +106 -0
  22. data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +13 -8
  23. data/lib/tapioca/compilers/dsl/base.rb +108 -82
  24. data/lib/tapioca/compilers/dsl/config.rb +111 -0
  25. data/lib/tapioca/compilers/dsl/frozen_record.rb +5 -7
  26. data/lib/tapioca/compilers/dsl/identity_cache.rb +66 -29
  27. data/lib/tapioca/compilers/dsl/mixed_in_class_attributes.rb +74 -0
  28. data/lib/tapioca/compilers/dsl/protobuf.rb +19 -69
  29. data/lib/tapioca/compilers/dsl/sidekiq_worker.rb +25 -12
  30. data/lib/tapioca/compilers/dsl/smart_properties.rb +21 -33
  31. data/lib/tapioca/compilers/dsl/state_machines.rb +56 -78
  32. data/lib/tapioca/compilers/dsl/url_helpers.rb +7 -10
  33. data/lib/tapioca/compilers/dsl_compiler.rb +25 -40
  34. data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +198 -0
  35. data/lib/tapioca/compilers/requires_compiler.rb +2 -2
  36. data/lib/tapioca/compilers/sorbet.rb +25 -5
  37. data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +122 -206
  38. data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +4 -4
  39. data/lib/tapioca/compilers/symbol_table_compiler.rb +5 -11
  40. data/lib/tapioca/compilers/todos_compiler.rb +1 -1
  41. data/lib/tapioca/config.rb +3 -0
  42. data/lib/tapioca/config_builder.rb +5 -2
  43. data/lib/tapioca/constant_locator.rb +6 -8
  44. data/lib/tapioca/gemfile.rb +14 -11
  45. data/lib/tapioca/generators/base.rb +61 -0
  46. data/lib/tapioca/generators/dsl.rb +362 -0
  47. data/lib/tapioca/generators/gem.rb +345 -0
  48. data/lib/tapioca/generators/init.rb +79 -0
  49. data/lib/tapioca/generators/require.rb +52 -0
  50. data/lib/tapioca/generators/todo.rb +76 -0
  51. data/lib/tapioca/generators.rb +9 -0
  52. data/lib/tapioca/generic_type_registry.rb +25 -98
  53. data/lib/tapioca/helpers/active_record_column_type_helper.rb +98 -0
  54. data/lib/tapioca/internal.rb +2 -10
  55. data/lib/tapioca/loader.rb +11 -31
  56. data/lib/tapioca/rbi_ext/model.rb +166 -0
  57. data/lib/tapioca/reflection.rb +138 -0
  58. data/lib/tapioca/sorbet_ext/fixed_hash_patch.rb +1 -1
  59. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +72 -4
  60. data/lib/tapioca/sorbet_ext/name_patch.rb +1 -1
  61. data/lib/tapioca/version.rb +1 -1
  62. data/lib/tapioca.rb +3 -0
  63. metadata +45 -23
  64. data/lib/tapioca/cli/main.rb +0 -146
  65. data/lib/tapioca/core_ext/class.rb +0 -28
  66. data/lib/tapioca/core_ext/string.rb +0 -18
  67. data/lib/tapioca/generator.rb +0 -633
  68. data/lib/tapioca/rbi/model.rb +0 -405
  69. data/lib/tapioca/rbi/printer.rb +0 -410
  70. data/lib/tapioca/rbi/rewriters/group_nodes.rb +0 -106
  71. data/lib/tapioca/rbi/rewriters/nest_non_public_methods.rb +0 -65
  72. data/lib/tapioca/rbi/rewriters/nest_singleton_methods.rb +0 -42
  73. data/lib/tapioca/rbi/rewriters/sort_nodes.rb +0 -86
  74. data/lib/tapioca/rbi/visitor.rb +0 -21
@@ -1,633 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require 'pathname'
5
- require 'thor'
6
- require "tapioca/core_ext/string"
7
-
8
- module Tapioca
9
- class Generator < ::Thor::Shell::Color
10
- extend(T::Sig)
11
-
12
- sig { returns(Config) }
13
- attr_reader :config
14
-
15
- sig do
16
- params(
17
- config: Config
18
- ).void
19
- end
20
- def initialize(config)
21
- @config = config
22
- @bundle = T.let(nil, T.nilable(Gemfile))
23
- @loader = T.let(nil, T.nilable(Loader))
24
- @compiler = T.let(nil, T.nilable(Compilers::SymbolTableCompiler))
25
- @existing_rbis = T.let(nil, T.nilable(T::Hash[String, String]))
26
- @expected_rbis = T.let(nil, T.nilable(T::Hash[String, String]))
27
- super()
28
- end
29
-
30
- sig { params(gem_names: T::Array[String]).void }
31
- def build_gem_rbis(gem_names)
32
- require_gem_file
33
-
34
- gems_to_generate(gem_names)
35
- .reject { |gem| config.exclude.include?(gem.name) }
36
- .each do |gem|
37
- say("Processing '#{gem.name}' gem:", :green)
38
- indent do
39
- compile_gem_rbi(gem)
40
- puts
41
- end
42
- end
43
-
44
- say("All operations performed in working directory.", [:green, :bold])
45
- say("Please review changes and commit them.", [:green, :bold])
46
- end
47
-
48
- sig { void }
49
- def build_requires
50
- requires_path = Config::DEFAULT_POSTREQUIRE
51
- compiler = Compilers::RequiresCompiler.new(Config::SORBET_CONFIG)
52
- name = set_color(requires_path, :yellow, :bold)
53
- say("Compiling #{name}, this may take a few seconds... ")
54
-
55
- rb_string = compiler.compile
56
- if rb_string.empty?
57
- say("Nothing to do", :green)
58
- return
59
- end
60
-
61
- # Clean all existing requires before regenerating the list so we update
62
- # it with the new one found in the client code and remove the old ones.
63
- File.delete(requires_path) if File.exist?(requires_path)
64
-
65
- content = String.new
66
- content << rbi_header(
67
- "#{Config::DEFAULT_COMMAND} require",
68
- reason: "explicit gem requires",
69
- strictness: "false"
70
- )
71
- content << rb_string
72
-
73
- outdir = File.dirname(requires_path)
74
- FileUtils.mkdir_p(outdir)
75
- File.write(requires_path, content)
76
-
77
- say("Done", :green)
78
-
79
- say("All requires from this application have been written to #{name}.", [:green, :bold])
80
- cmd = set_color("#{Config::DEFAULT_COMMAND} sync", :yellow, :bold)
81
- say("Please review changes and commit them, then run `#{cmd}`.", [:green, :bold])
82
- end
83
-
84
- sig { void }
85
- def build_todos
86
- todos_path = config.todos_path
87
- compiler = Compilers::TodosCompiler.new
88
- name = set_color(todos_path, :yellow, :bold)
89
- say("Compiling #{name}, this may take a few seconds... ")
90
-
91
- # Clean all existing unresolved constants before regenerating the list
92
- # so Sorbet won't grab them as already resolved.
93
- File.delete(todos_path) if File.exist?(todos_path)
94
-
95
- rbi_string = compiler.compile
96
- if rbi_string.empty?
97
- say("Nothing to do", :green)
98
- return
99
- end
100
-
101
- content = String.new
102
- content << rbi_header(
103
- "#{Config::DEFAULT_COMMAND} todo",
104
- reason: "unresolved constants",
105
- strictness: "false"
106
- )
107
- content << rbi_string
108
- content << "\n"
109
-
110
- outdir = File.dirname(todos_path)
111
- FileUtils.mkdir_p(outdir)
112
- File.write(todos_path, content)
113
-
114
- say("Done", :green)
115
-
116
- say("All unresolved constants have been written to #{name}.", [:green, :bold])
117
- say("Please review changes and commit them.", [:green, :bold])
118
- end
119
-
120
- sig do
121
- params(
122
- requested_constants: T::Array[String],
123
- should_verify: T::Boolean,
124
- quiet: T::Boolean
125
- ).void
126
- end
127
- def build_dsl(requested_constants, should_verify: false, quiet: false)
128
- load_application(eager_load: requested_constants.empty?)
129
- load_dsl_generators
130
-
131
- if should_verify
132
- say("Checking for out-of-date RBIs...")
133
- else
134
- say("Compiling DSL RBI files...")
135
- end
136
- say("")
137
-
138
- outpath = should_verify ? Pathname.new(Dir.mktmpdir) : config.outpath
139
- rbi_files_to_purge = existing_rbi_filenames(requested_constants)
140
-
141
- compiler = Compilers::DslCompiler.new(
142
- requested_constants: constantize(requested_constants),
143
- requested_generators: config.generators,
144
- error_handler: ->(error) {
145
- say_error(error, :bold, :red)
146
- }
147
- )
148
-
149
- compiler.run do |constant, contents|
150
- constant_name = Module.instance_method(:name).bind(constant).call
151
-
152
- filename = compile_dsl_rbi(
153
- constant_name,
154
- contents,
155
- outpath: outpath,
156
- quiet: should_verify || quiet
157
- )
158
-
159
- if filename
160
- rbi_files_to_purge.delete(filename)
161
- end
162
- end
163
- say("")
164
-
165
- if should_verify
166
- perform_dsl_verification(outpath)
167
- else
168
- purge_stale_dsl_rbi_files(rbi_files_to_purge)
169
-
170
- say("Done", :green)
171
-
172
- say("All operations performed in working directory.", [:green, :bold])
173
- say("Please review changes and commit them.", [:green, :bold])
174
- end
175
- end
176
-
177
- sig { void }
178
- def sync_rbis_with_gemfile
179
- anything_done = [
180
- perform_removals,
181
- perform_additions,
182
- ].any?
183
-
184
- if anything_done
185
- say("All operations performed in working directory.", [:green, :bold])
186
- say("Please review changes and commit them.", [:green, :bold])
187
- else
188
- say("No operations performed, all RBIs are up-to-date.", [:green, :bold])
189
- end
190
-
191
- puts
192
- end
193
-
194
- private
195
-
196
- EMPTY_RBI_COMMENT = <<~CONTENT
197
- # THIS IS AN EMPTY RBI FILE.
198
- # see https://github.com/Shopify/tapioca/blob/master/README.md#manual-gem-requires
199
- CONTENT
200
-
201
- sig { returns(Gemfile) }
202
- def bundle
203
- @bundle ||= Gemfile.new
204
- end
205
-
206
- sig { returns(Loader) }
207
- def loader
208
- @loader ||= Loader.new(bundle)
209
- end
210
-
211
- sig { returns(Compilers::SymbolTableCompiler) }
212
- def compiler
213
- @compiler ||= Compilers::SymbolTableCompiler.new
214
- end
215
-
216
- sig { void }
217
- def require_gem_file
218
- say("Requiring all gems to prepare for compiling... ")
219
- begin
220
- loader.load_bundle(config.prerequire, config.postrequire)
221
- rescue LoadError => e
222
- explain_failed_require(config.postrequire, e)
223
- exit(1)
224
- end
225
- say(" Done", :green)
226
- unless bundle.missing_specs.empty?
227
- say(" completed with missing specs: ")
228
- say(bundle.missing_specs.join(', '), :yellow)
229
- end
230
- puts
231
- end
232
-
233
- sig { params(file: String, error: LoadError).void }
234
- def explain_failed_require(file, error)
235
- say_error("\n\nLoadError: #{error}", :bold, :red)
236
- say_error("\nTapioca could not load all the gems required by your application.", :yellow)
237
- say_error("If you populated ", :yellow)
238
- say_error("#{file} ", :bold, :blue)
239
- say_error("with ", :yellow)
240
- say_error("`#{Config::DEFAULT_COMMAND} require`", :bold, :blue)
241
- say_error("you should probably review it and remove the faulty line.", :yellow)
242
- end
243
-
244
- sig do
245
- params(
246
- message: String,
247
- color: T.any(Symbol, T::Array[Symbol]),
248
- ).void
249
- end
250
- def say_error(message = "", *color)
251
- force_new_line = (message.to_s !~ /( |\t)\Z/)
252
- buffer = prepare_message(*T.unsafe([message, *T.unsafe(color)]))
253
- buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
254
-
255
- stderr.print(buffer)
256
- stderr.flush
257
- end
258
-
259
- sig { params(eager_load: T::Boolean).void }
260
- def load_application(eager_load:)
261
- say("Loading Rails application... ")
262
-
263
- loader.load_rails_application(
264
- environment_load: true,
265
- eager_load: eager_load
266
- )
267
-
268
- say("Done", :green)
269
- end
270
-
271
- sig { void }
272
- def load_dsl_generators
273
- say("Loading DSL generator classes... ")
274
-
275
- Dir.glob([
276
- "#{__dir__}/compilers/dsl/*.rb",
277
- "#{Config::TAPIOCA_PATH}/generators/**/*.rb",
278
- ]).each do |generator|
279
- require File.expand_path(generator)
280
- end
281
-
282
- say("Done", :green)
283
- end
284
-
285
- sig { params(constant_names: T::Array[String]).returns(T::Array[Module]) }
286
- def constantize(constant_names)
287
- constant_map = constant_names.map do |name|
288
- begin
289
- [name, Object.const_get(name)]
290
- rescue NameError
291
- [name, nil]
292
- end
293
- end.to_h
294
-
295
- unprocessable_constants = constant_map.select { |_, v| v.nil? }
296
- unless unprocessable_constants.empty?
297
- unprocessable_constants.each do |name, _|
298
- say("Error: Cannot find constant '#{name}'", :red)
299
- remove(dsl_rbi_filename(name))
300
- end
301
-
302
- exit(1)
303
- end
304
-
305
- constant_map.values
306
- end
307
-
308
- sig { params(requested_constants: T::Array[String], path: Pathname).returns(T::Set[Pathname]) }
309
- def existing_rbi_filenames(requested_constants, path: config.outpath)
310
- filenames = if requested_constants.empty?
311
- Pathname.glob(path / "**/*.rbi")
312
- else
313
- requested_constants.map do |constant_name|
314
- dsl_rbi_filename(constant_name)
315
- end
316
- end
317
-
318
- filenames.to_set
319
- end
320
-
321
- sig { returns(T::Hash[String, String]) }
322
- def existing_rbis
323
- @existing_rbis ||= Pathname.glob((config.outpath / "*@*.rbi").to_s)
324
- .map { |f| T.cast(f.basename(".*").to_s.split('@', 2), [String, String]) }
325
- .to_h
326
- end
327
-
328
- sig { returns(T::Hash[String, String]) }
329
- def expected_rbis
330
- @expected_rbis ||= bundle.dependencies
331
- .reject { |gem| config.exclude.include?(gem.name) }
332
- .map { |gem| [gem.name, gem.version.to_s] }
333
- .to_h
334
- end
335
-
336
- sig { params(constant_name: String).returns(Pathname) }
337
- def dsl_rbi_filename(constant_name)
338
- config.outpath / "#{constant_name.underscore}.rbi"
339
- end
340
-
341
- sig { params(gem_name: String, version: String).returns(Pathname) }
342
- def gem_rbi_filename(gem_name, version)
343
- config.outpath / "#{gem_name}@#{version}.rbi"
344
- end
345
-
346
- sig { params(gem_name: String).returns(Pathname) }
347
- def existing_rbi(gem_name)
348
- gem_rbi_filename(gem_name, T.must(existing_rbis[gem_name]))
349
- end
350
-
351
- sig { params(gem_name: String).returns(Pathname) }
352
- def expected_rbi(gem_name)
353
- gem_rbi_filename(gem_name, T.must(expected_rbis[gem_name]))
354
- end
355
-
356
- sig { params(gem_name: String).returns(T::Boolean) }
357
- def gem_rbi_exists?(gem_name)
358
- existing_rbis.key?(gem_name)
359
- end
360
-
361
- sig { returns(T::Array[String]) }
362
- def removed_rbis
363
- (existing_rbis.keys - expected_rbis.keys).sort
364
- end
365
-
366
- sig { returns(T::Array[String]) }
367
- def added_rbis
368
- expected_rbis.select do |name, value|
369
- existing_rbis[name] != value
370
- end.keys.sort
371
- end
372
-
373
- sig { params(filename: Pathname).void }
374
- def add(filename)
375
- say("++ Adding: #{filename}")
376
- end
377
-
378
- sig { params(filename: Pathname).void }
379
- def remove(filename)
380
- return unless filename.exist?
381
- say("-- Removing: #{filename}")
382
- filename.unlink
383
- end
384
-
385
- sig { params(old_filename: Pathname, new_filename: Pathname).void }
386
- def move(old_filename, new_filename)
387
- say("-> Moving: #{old_filename} to #{new_filename}")
388
- old_filename.rename(new_filename.to_s)
389
- end
390
-
391
- sig { void }
392
- def perform_removals
393
- say("Removing RBI files of gems that have been removed:", [:blue, :bold])
394
- puts
395
-
396
- anything_done = T.let(false, T::Boolean)
397
-
398
- gems = removed_rbis
399
-
400
- indent do
401
- if gems.empty?
402
- say("Nothing to do.")
403
- else
404
- gems.each do |removed|
405
- filename = existing_rbi(removed)
406
- remove(filename)
407
- end
408
-
409
- anything_done = true
410
- end
411
- end
412
-
413
- puts
414
-
415
- anything_done
416
- end
417
-
418
- sig { void }
419
- def perform_additions
420
- say("Generating RBI files of gems that are added or updated:", [:blue, :bold])
421
- puts
422
-
423
- anything_done = T.let(false, T::Boolean)
424
-
425
- gems = added_rbis
426
-
427
- indent do
428
- if gems.empty?
429
- say("Nothing to do.")
430
- else
431
- require_gem_file
432
-
433
- gems.each do |gem_name|
434
- filename = expected_rbi(gem_name)
435
-
436
- if gem_rbi_exists?(gem_name)
437
- old_filename = existing_rbi(gem_name)
438
- move(old_filename, filename) unless old_filename == filename
439
- end
440
-
441
- gem = T.must(bundle.gem(gem_name))
442
- compile_gem_rbi(gem)
443
- add(filename)
444
-
445
- puts
446
- end
447
- end
448
-
449
- anything_done = true
450
- end
451
-
452
- puts
453
-
454
- anything_done
455
- end
456
-
457
- sig do
458
- params(gem_names: T::Array[String])
459
- .returns(T::Array[Gemfile::GemSpec])
460
- end
461
- def gems_to_generate(gem_names)
462
- return bundle.dependencies if gem_names.empty?
463
-
464
- gem_names.map do |gem_name|
465
- gem = bundle.gem(gem_name)
466
- if gem.nil?
467
- say("Error: Cannot find gem '#{gem_name}'", :red)
468
- exit(1)
469
- end
470
- gem
471
- end
472
- end
473
-
474
- sig { params(command: String, reason: T.nilable(String), strictness: T.nilable(String)).returns(String) }
475
- def rbi_header(command, reason: nil, strictness: nil)
476
- statement = <<~HEAD
477
- # DO NOT EDIT MANUALLY
478
- # This is an autogenerated file for #{reason}.
479
- # Please instead update this file by running `#{command}`.
480
- HEAD
481
-
482
- sigil = <<~SIGIL if strictness
483
- # typed: #{strictness}
484
- SIGIL
485
-
486
- [statement, sigil].compact.join("\n").strip.concat("\n\n")
487
- end
488
-
489
- sig { params(gem: Gemfile::GemSpec).void }
490
- def compile_gem_rbi(gem)
491
- compiler = Compilers::SymbolTableCompiler.new
492
- gem_name = set_color(gem.name, :yellow, :bold)
493
- say("Compiling #{gem_name}, this may take a few seconds... ")
494
-
495
- strictness = config.typed_overrides[gem.name] || "true"
496
- rbi_body_content = compiler.compile(gem)
497
- content = String.new
498
- content << rbi_header(
499
- "#{Config::DEFAULT_COMMAND} sync",
500
- reason: "types exported from the `#{gem.name}` gem",
501
- strictness: strictness
502
- )
503
-
504
- FileUtils.mkdir_p(config.outdir)
505
- filename = config.outpath / gem.rbi_file_name
506
-
507
- if rbi_body_content.strip.empty?
508
- content << EMPTY_RBI_COMMENT
509
- say("Done (empty output)", :yellow)
510
- else
511
- content << rbi_body_content
512
- say("Done", :green)
513
- end
514
- File.write(filename.to_s, content)
515
-
516
- T.unsafe(Pathname).glob((config.outpath / "#{gem.name}@*.rbi").to_s) do |file|
517
- remove(file) unless file.basename.to_s == gem.rbi_file_name
518
- end
519
- end
520
-
521
- sig do
522
- params(constant_name: String, contents: String, outpath: Pathname, quiet: T::Boolean)
523
- .returns(T.nilable(Pathname))
524
- end
525
- def compile_dsl_rbi(constant_name, contents, outpath: config.outpath, quiet: false)
526
- return if contents.nil?
527
-
528
- rbi_name = constant_name.underscore + ".rbi"
529
- filename = outpath / rbi_name
530
-
531
- out = String.new
532
- out << rbi_header(
533
- "#{Config::DEFAULT_COMMAND} dsl #{constant_name}",
534
- reason: "dynamic methods in `#{constant_name}`"
535
- )
536
- out << contents
537
-
538
- FileUtils.mkdir_p(File.dirname(filename))
539
- File.write(filename, out)
540
-
541
- unless quiet
542
- say("Wrote: ", [:green])
543
- say(filename)
544
- end
545
-
546
- filename
547
- end
548
-
549
- sig { params(tmp_dir: Pathname).returns(T::Hash[String, Symbol]) }
550
- def verify_dsl_rbi(tmp_dir:)
551
- diff = {}
552
-
553
- existing_rbis = rbi_files_in(config.outpath)
554
- new_rbis = rbi_files_in(tmp_dir)
555
-
556
- added_files = (new_rbis - existing_rbis)
557
-
558
- added_files.each do |file|
559
- diff[file] = :added
560
- end
561
-
562
- removed_files = (existing_rbis - new_rbis)
563
-
564
- removed_files.each do |file|
565
- diff[file] = :removed
566
- end
567
-
568
- common_files = (existing_rbis & new_rbis)
569
-
570
- changed_files = common_files.map do |filename|
571
- filename unless FileUtils.identical?(config.outpath / filename, tmp_dir / filename)
572
- end.compact
573
-
574
- changed_files.each do |file|
575
- diff[file] = :changed
576
- end
577
-
578
- diff
579
- end
580
-
581
- sig { params(cause: Symbol, files: T::Array[String]).returns(String) }
582
- def build_error_for_files(cause, files)
583
- filenames = files.map do |file|
584
- config.outpath / file
585
- end.join("\n - ")
586
-
587
- " File(s) #{cause}:\n - #{filenames}"
588
- end
589
-
590
- sig { params(path: Pathname).returns(T::Array[Pathname]) }
591
- def rbi_files_in(path)
592
- Pathname.glob(path / "**/*.rbi").map do |file|
593
- file.relative_path_from(path)
594
- end.sort
595
- end
596
-
597
- sig { params(dir: Pathname).void }
598
- def perform_dsl_verification(dir)
599
- diff = verify_dsl_rbi(tmp_dir: dir)
600
-
601
- if diff.empty?
602
- say("Nothing to do, all RBIs are up-to-date.")
603
- else
604
- say("RBI files are out-of-date. In your development environment, please run:", :green)
605
- say(" `#{Config::DEFAULT_COMMAND} dsl`", [:green, :bold])
606
- say("Once it is complete, be sure to commit and push any changes", :green)
607
-
608
- say("")
609
-
610
- say("Reason:", [:red])
611
- diff.group_by(&:last).sort.each do |cause, diff_for_cause|
612
- say(build_error_for_files(cause, diff_for_cause.map(&:first)))
613
- end
614
-
615
- exit(1)
616
- end
617
- ensure
618
- FileUtils.remove_entry(dir)
619
- end
620
-
621
- sig { params(files: T::Set[Pathname]).void }
622
- def purge_stale_dsl_rbi_files(files)
623
- if files.any?
624
- say("Removing stale RBI files...")
625
-
626
- files.sort.each do |filename|
627
- remove(filename)
628
- end
629
- say("")
630
- end
631
- end
632
- end
633
- end