tapioca 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/README.md +491 -73
- data/lib/tapioca/cli.rb +40 -3
- data/lib/tapioca/commands/annotations.rb +154 -0
- data/lib/tapioca/commands/dsl.rb +20 -1
- data/lib/tapioca/commands/gem.rb +17 -57
- data/lib/tapioca/commands/init.rb +1 -0
- data/lib/tapioca/commands/todo.rb +4 -2
- data/lib/tapioca/commands.rb +1 -0
- data/lib/tapioca/dsl/compiler.rb +2 -2
- data/lib/tapioca/dsl/compilers/aasm.rb +1 -1
- data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +1 -1
- data/lib/tapioca/dsl/compilers/action_mailer.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_job.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_model_attributes.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_associations.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_columns.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_enum.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +3 -1
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +8 -8
- data/lib/tapioca/dsl/compilers/active_record_scope.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_resource.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_storage.rb +6 -2
- data/lib/tapioca/dsl/compilers/active_support_concern.rb +1 -1
- data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +1 -1
- data/lib/tapioca/dsl/compilers/config.rb +2 -2
- data/lib/tapioca/dsl/compilers/frozen_record.rb +1 -1
- data/lib/tapioca/dsl/compilers/identity_cache.rb +1 -1
- data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +1 -1
- data/lib/tapioca/dsl/compilers/protobuf.rb +27 -3
- data/lib/tapioca/dsl/compilers/rails_generators.rb +1 -1
- data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +1 -1
- data/lib/tapioca/dsl/compilers/smart_properties.rb +1 -1
- data/lib/tapioca/dsl/compilers/state_machines.rb +1 -1
- data/lib/tapioca/dsl/compilers/url_helpers.rb +5 -2
- data/lib/tapioca/dsl/helpers/param_helper.rb +4 -1
- data/lib/tapioca/dsl/pipeline.rb +32 -1
- data/lib/tapioca/dsl.rb +6 -0
- data/lib/tapioca/executor.rb +4 -46
- data/lib/tapioca/gem/listeners/methods.rb +26 -1
- data/lib/tapioca/gem/listeners/sorbet_props.rb +1 -1
- data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +1 -0
- data/lib/tapioca/gem/listeners/sorbet_signatures.rb +1 -1
- data/lib/tapioca/gem/pipeline.rb +5 -1
- data/lib/tapioca/gemfile.rb +50 -3
- data/lib/tapioca/helpers/config_helper.rb +13 -0
- data/lib/tapioca/helpers/rbi_helper.rb +114 -7
- data/lib/tapioca/helpers/shims_helper.rb +36 -8
- data/lib/tapioca/helpers/signatures_helper.rb +17 -0
- data/lib/tapioca/helpers/sorbet_helper.rb +5 -11
- data/lib/tapioca/helpers/test/content.rb +1 -0
- data/lib/tapioca/helpers/test/dsl_compiler.rb +1 -0
- data/lib/tapioca/helpers/test/template.rb +1 -0
- data/lib/tapioca/helpers/type_variable_helper.rb +43 -0
- data/lib/tapioca/internal.rb +4 -1
- data/lib/tapioca/rbi_ext/model.rb +14 -2
- data/lib/tapioca/repo_index.rb +41 -0
- data/lib/tapioca/runtime/generic_type_registry.rb +4 -2
- data/lib/tapioca/runtime/loader.rb +3 -0
- data/lib/tapioca/runtime/reflection.rb +17 -13
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +38 -21
- data/lib/tapioca/static/symbol_table_parser.rb +2 -0
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +5 -0
- metadata +26 -21
data/lib/tapioca/cli.rb
CHANGED
@@ -5,6 +5,7 @@ module Tapioca
|
|
5
5
|
class Cli < Thor
|
6
6
|
include CliHelper
|
7
7
|
include ConfigHelper
|
8
|
+
include SorbetHelper
|
8
9
|
include ShimsHelper
|
9
10
|
|
10
11
|
FILE_HEADER_OPTION_DESC = "Add a \"This file is generated\" header on top of each generated RBI file"
|
@@ -89,7 +90,7 @@ module Tapioca
|
|
89
90
|
option :quiet,
|
90
91
|
aliases: ["-q"],
|
91
92
|
type: :boolean,
|
92
|
-
desc: "
|
93
|
+
desc: "Suppresses file creation output",
|
93
94
|
default: false
|
94
95
|
option :workers,
|
95
96
|
aliases: ["-w"],
|
@@ -171,7 +172,7 @@ module Tapioca
|
|
171
172
|
option :doc,
|
172
173
|
type: :boolean,
|
173
174
|
desc: "Include YARD documentation from sources when generating RBIs. Warning: this might be slow",
|
174
|
-
default:
|
175
|
+
default: true
|
175
176
|
option :exported_gem_rbis,
|
176
177
|
type: :boolean,
|
177
178
|
desc: "Include RBIs found in the `rbi/` directory of the gem",
|
@@ -242,6 +243,7 @@ module Tapioca
|
|
242
243
|
option :gem_rbi_dir, type: :string, desc: "Path to gem RBIs", default: DEFAULT_GEM_DIR
|
243
244
|
option :dsl_rbi_dir, type: :string, desc: "Path to DSL RBIs", default: DEFAULT_DSL_DIR
|
244
245
|
option :shim_rbi_dir, type: :string, desc: "Path to shim RBIs", default: DEFAULT_SHIM_DIR
|
246
|
+
option :payload, type: :boolean, desc: "Check shims against Sorbet's payload", default: true
|
245
247
|
def check_shims
|
246
248
|
index = RBI::Index.new
|
247
249
|
|
@@ -251,6 +253,30 @@ module Tapioca
|
|
251
253
|
exit(0)
|
252
254
|
end
|
253
255
|
|
256
|
+
payload_path = T.let(nil, T.nilable(String))
|
257
|
+
|
258
|
+
if options[:payload]
|
259
|
+
if sorbet_supports?(:print_payload_sources)
|
260
|
+
Dir.mktmpdir do |dir|
|
261
|
+
payload_path = dir
|
262
|
+
result = sorbet("--no-config --print=payload-sources:#{payload_path}")
|
263
|
+
|
264
|
+
unless result.status
|
265
|
+
say_error("Sorbet failed to dump payload")
|
266
|
+
say_error(result.err)
|
267
|
+
exit(1)
|
268
|
+
end
|
269
|
+
|
270
|
+
index_payload(index, payload_path)
|
271
|
+
end
|
272
|
+
else
|
273
|
+
say_error("The version of Sorbet used in your Gemfile.lock does not support `--print=payload-sources`")
|
274
|
+
say_error("Current: v#{SORBET_GEM_SPEC.version}")
|
275
|
+
say_error("Required: #{FEATURE_REQUIREMENTS[:print_payload_sources]}")
|
276
|
+
exit(1)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
254
280
|
index_rbis(index, "shim", shim_rbi_dir)
|
255
281
|
index_rbis(index, "gem", options[:gem_rbi_dir])
|
256
282
|
index_rbis(index, "dsl", options[:dsl_rbi_dir])
|
@@ -260,7 +286,11 @@ module Tapioca
|
|
260
286
|
duplicates.each do |key, nodes|
|
261
287
|
say_error("\nDuplicated RBI for #{key}:", :red)
|
262
288
|
nodes.each do |node|
|
263
|
-
|
289
|
+
node_loc = node.loc
|
290
|
+
next unless node_loc
|
291
|
+
|
292
|
+
loc_string = location_to_payload_url(node_loc, path_prefix: payload_path)
|
293
|
+
say_error(" * #{loc_string}", :red)
|
264
294
|
end
|
265
295
|
end
|
266
296
|
say_error("\nPlease remove the duplicated definitions from the #{shim_rbi_dir} directory.", :red)
|
@@ -271,6 +301,13 @@ module Tapioca
|
|
271
301
|
exit(0)
|
272
302
|
end
|
273
303
|
|
304
|
+
desc "annotations", "Pull gem annotations from a central RBI repository"
|
305
|
+
option :repo_uri, type: :string, desc: "Repository URI to pull annotations from", default: CENTRAL_REPO_ROOT_URI
|
306
|
+
def annotations
|
307
|
+
command = Commands::Annotations.new(central_repo_root_uri: options[:repo_uri])
|
308
|
+
command.execute
|
309
|
+
end
|
310
|
+
|
274
311
|
map ["--version", "-v"] => :__print_version
|
275
312
|
|
276
313
|
desc "--version, -v", "show version"
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "net/http"
|
5
|
+
|
6
|
+
module Tapioca
|
7
|
+
module Commands
|
8
|
+
class Annotations < Command
|
9
|
+
extend T::Sig
|
10
|
+
|
11
|
+
sig do
|
12
|
+
params(
|
13
|
+
central_repo_root_uri: String,
|
14
|
+
central_repo_index_path: String
|
15
|
+
).void
|
16
|
+
end
|
17
|
+
def initialize(central_repo_root_uri:, central_repo_index_path: CENTRAL_REPO_INDEX_PATH)
|
18
|
+
super()
|
19
|
+
@central_repo_root_uri = central_repo_root_uri
|
20
|
+
@index = T.let(fetch_index, RepoIndex)
|
21
|
+
end
|
22
|
+
|
23
|
+
sig { override.void }
|
24
|
+
def execute
|
25
|
+
project_gems = list_gemfile_gems
|
26
|
+
remove_expired_annotations(project_gems)
|
27
|
+
fetch_annotations(project_gems)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
sig { returns(T::Array[String]) }
|
33
|
+
def list_gemfile_gems
|
34
|
+
say("Listing gems from Gemfile.lock... ", [:blue, :bold])
|
35
|
+
gemfile = Bundler.read_file("Gemfile.lock")
|
36
|
+
parser = Bundler::LockfileParser.new(gemfile)
|
37
|
+
gem_names = parser.specs.map(&:name)
|
38
|
+
say("Done", :green)
|
39
|
+
gem_names
|
40
|
+
end
|
41
|
+
|
42
|
+
sig { params(project_gems: T::Array[String]).void }
|
43
|
+
def remove_expired_annotations(project_gems)
|
44
|
+
say("Removing annotations for gems that have been removed... ", [:blue, :bold])
|
45
|
+
|
46
|
+
annotations = Pathname.glob("#{DEFAULT_ANNOTATIONS_DIR}/*.rbi").map { |f| f.basename(".*").to_s }
|
47
|
+
expired = annotations - project_gems
|
48
|
+
|
49
|
+
if expired.empty?
|
50
|
+
say(" Nothing to do")
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
say("\n")
|
55
|
+
expired.each do |gem_name|
|
56
|
+
say("\n")
|
57
|
+
path = "#{DEFAULT_ANNOTATIONS_DIR}/#{gem_name}.rbi"
|
58
|
+
remove_file(path)
|
59
|
+
end
|
60
|
+
say("\nDone\n\n", :green)
|
61
|
+
end
|
62
|
+
|
63
|
+
sig { returns(RepoIndex) }
|
64
|
+
def fetch_index
|
65
|
+
say("Retrieving index from central repository... ", [:blue, :bold])
|
66
|
+
content = fetch_file(CENTRAL_REPO_INDEX_PATH)
|
67
|
+
exit(1) unless content
|
68
|
+
|
69
|
+
index = RepoIndex.from_json(content)
|
70
|
+
say("Done", :green)
|
71
|
+
index
|
72
|
+
end
|
73
|
+
|
74
|
+
sig { params(gem_names: T::Array[String]).returns(T::Array[String]) }
|
75
|
+
def fetch_annotations(gem_names)
|
76
|
+
say("Fetching gem annotations from central repository... ", [:blue, :bold])
|
77
|
+
fetchable_gems = gem_names.select { |gem_name| @index.has_gem?(gem_name) }
|
78
|
+
|
79
|
+
if fetchable_gems.empty?
|
80
|
+
say(" Nothing to do")
|
81
|
+
exit(0)
|
82
|
+
end
|
83
|
+
|
84
|
+
say("\n")
|
85
|
+
fetched_gems = fetchable_gems.select { |name| fetch_annotation(name) }
|
86
|
+
say("\nDone", :green)
|
87
|
+
fetched_gems
|
88
|
+
end
|
89
|
+
|
90
|
+
sig { params(gem_name: String).void }
|
91
|
+
def fetch_annotation(gem_name)
|
92
|
+
content = fetch_file("#{CENTRAL_REPO_ANNOTATIONS_DIR}/#{gem_name}.rbi")
|
93
|
+
return unless content
|
94
|
+
|
95
|
+
content = add_header(gem_name, content)
|
96
|
+
|
97
|
+
dir = DEFAULT_ANNOTATIONS_DIR
|
98
|
+
FileUtils.mkdir_p(dir)
|
99
|
+
say("\n Fetched #{set_color(gem_name, :yellow, :bold)}", :green)
|
100
|
+
create_file("#{dir}/#{gem_name}.rbi", content)
|
101
|
+
end
|
102
|
+
|
103
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
104
|
+
def fetch_file(path)
|
105
|
+
if @central_repo_root_uri.start_with?(%r{https?://})
|
106
|
+
fetch_http_file(path)
|
107
|
+
else
|
108
|
+
fetch_local_file(path)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
113
|
+
def fetch_local_file(path)
|
114
|
+
File.read("#{@central_repo_root_uri}/#{path}")
|
115
|
+
rescue => e
|
116
|
+
say_error("\nCan't fetch file `#{path}` (#{e.message})", :bold, :red)
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
|
120
|
+
sig { params(path: String).returns(T.nilable(String)) }
|
121
|
+
def fetch_http_file(path)
|
122
|
+
uri = URI("#{@central_repo_root_uri}/#{path}")
|
123
|
+
response = Net::HTTP.get_response(uri)
|
124
|
+
case response
|
125
|
+
when Net::HTTPSuccess
|
126
|
+
response.body
|
127
|
+
else
|
128
|
+
say_error("\nCan't fetch file `#{path}` from #{@central_repo_root_uri} (#{response.class})", :bold, :red)
|
129
|
+
nil
|
130
|
+
end
|
131
|
+
rescue SocketError, Errno::ECONNREFUSED => e
|
132
|
+
say_error("\nCan't fetch file `#{path}` from #{@central_repo_root_uri} (#{e.message})", :bold, :red)
|
133
|
+
nil
|
134
|
+
end
|
135
|
+
|
136
|
+
sig { params(name: String, content: String).returns(String) }
|
137
|
+
def add_header(name, content)
|
138
|
+
header = <<~COMMENT
|
139
|
+
# DO NOT EDIT MANUALLY
|
140
|
+
# This file was pulled from #{@central_repo_root_uri}.
|
141
|
+
# Please run `#{default_command(:annotations)}` to update it.
|
142
|
+
COMMENT
|
143
|
+
|
144
|
+
contents = content.split("\n")
|
145
|
+
if contents[0]&.start_with?("# typed:") && contents[1]&.empty?
|
146
|
+
contents.insert(2, header).join("\n")
|
147
|
+
else
|
148
|
+
say_error("Couldn't insert file header for content: #{content} due to unexpected file format")
|
149
|
+
content
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
data/lib/tapioca/commands/dsl.rb
CHANGED
@@ -4,6 +4,9 @@
|
|
4
4
|
module Tapioca
|
5
5
|
module Commands
|
6
6
|
class Dsl < Command
|
7
|
+
include SorbetHelper
|
8
|
+
include RBIHelper
|
9
|
+
|
7
10
|
sig do
|
8
11
|
params(
|
9
12
|
requested_constants: T::Array[String],
|
@@ -17,6 +20,8 @@ module Tapioca
|
|
17
20
|
quiet: T::Boolean,
|
18
21
|
verbose: T::Boolean,
|
19
22
|
number_of_workers: T.nilable(Integer),
|
23
|
+
auto_strictness: T::Boolean,
|
24
|
+
gem_dir: String,
|
20
25
|
rbi_formatter: RBIFormatter
|
21
26
|
).void
|
22
27
|
end
|
@@ -32,6 +37,8 @@ module Tapioca
|
|
32
37
|
quiet: false,
|
33
38
|
verbose: false,
|
34
39
|
number_of_workers: nil,
|
40
|
+
auto_strictness: true,
|
41
|
+
gem_dir: DEFAULT_GEM_DIR,
|
35
42
|
rbi_formatter: DEFAULT_RBI_FORMATTER
|
36
43
|
)
|
37
44
|
@requested_constants = requested_constants
|
@@ -45,6 +52,8 @@ module Tapioca
|
|
45
52
|
@quiet = quiet
|
46
53
|
@verbose = verbose
|
47
54
|
@number_of_workers = number_of_workers
|
55
|
+
@auto_strictness = auto_strictness
|
56
|
+
@gem_dir = gem_dir
|
48
57
|
@rbi_formatter = rbi_formatter
|
49
58
|
|
50
59
|
super()
|
@@ -102,9 +111,19 @@ module Tapioca
|
|
102
111
|
perform_dsl_verification(outpath)
|
103
112
|
else
|
104
113
|
purge_stale_dsl_rbi_files(rbi_files_to_purge)
|
105
|
-
|
106
114
|
say("Done", :green)
|
107
115
|
|
116
|
+
if @auto_strictness
|
117
|
+
say("")
|
118
|
+
validate_rbi_files(
|
119
|
+
command: default_command(:dsl, @requested_constants.join(" ")),
|
120
|
+
gem_dir: @gem_dir,
|
121
|
+
dsl_dir: @outpath.to_s,
|
122
|
+
auto_strictness: @auto_strictness,
|
123
|
+
compilers: pipeline.compilers
|
124
|
+
)
|
125
|
+
end
|
126
|
+
|
108
127
|
say("All operations performed in working directory.", [:green, :bold])
|
109
128
|
say("Please review changes and commit them.", [:green, :bold])
|
110
129
|
end
|
data/lib/tapioca/commands/gem.rb
CHANGED
@@ -5,6 +5,7 @@ module Tapioca
|
|
5
5
|
module Commands
|
6
6
|
class Gem < Command
|
7
7
|
include SorbetHelper
|
8
|
+
include RBIHelper
|
8
9
|
|
9
10
|
sig do
|
10
11
|
params(
|
@@ -78,7 +79,13 @@ module Tapioca
|
|
78
79
|
end
|
79
80
|
|
80
81
|
if anything_done
|
81
|
-
|
82
|
+
validate_rbi_files(
|
83
|
+
command: default_command(:gem, @gem_names.join(" ")),
|
84
|
+
gem_dir: @outpath.to_s,
|
85
|
+
dsl_dir: @dsl_dir,
|
86
|
+
auto_strictness: @auto_strictness,
|
87
|
+
gems: bundle.dependencies
|
88
|
+
)
|
82
89
|
|
83
90
|
say("All operations performed in working directory.", [:green, :bold])
|
84
91
|
say("Please review changes and commit them.", [:green, :bold])
|
@@ -102,7 +109,13 @@ module Tapioca
|
|
102
109
|
].any?
|
103
110
|
|
104
111
|
if anything_done
|
105
|
-
|
112
|
+
validate_rbi_files(
|
113
|
+
command: default_command(:gem),
|
114
|
+
gem_dir: @outpath.to_s,
|
115
|
+
dsl_dir: @dsl_dir,
|
116
|
+
auto_strictness: @auto_strictness,
|
117
|
+
gems: bundle.dependencies
|
118
|
+
)
|
106
119
|
|
107
120
|
say("All operations performed in working directory.", [:green, :bold])
|
108
121
|
say("Please review changes and commit them.", [:green, :bold])
|
@@ -122,7 +135,7 @@ module Tapioca
|
|
122
135
|
|
123
136
|
sig { returns(Gemfile) }
|
124
137
|
def bundle
|
125
|
-
@bundle ||= Gemfile.new
|
138
|
+
@bundle ||= Gemfile.new(@exclude)
|
126
139
|
end
|
127
140
|
|
128
141
|
sig { void }
|
@@ -359,6 +372,7 @@ module Tapioca
|
|
359
372
|
sig { params(gem: Gemfile::GemSpec, file: RBI::File).void }
|
360
373
|
def merge_with_exported_rbi(gem, file)
|
361
374
|
return file unless gem.export_rbi_files?
|
375
|
+
|
362
376
|
tree = gem.exported_rbi_tree
|
363
377
|
|
364
378
|
unless tree.conflicts.empty?
|
@@ -379,60 +393,6 @@ module Tapioca
|
|
379
393
|
say_error("\n\n RBIs exported by `#{gem.name}` contain errors and can't be used:", :yellow)
|
380
394
|
say_error("Cause: #{e.message} (#{e.location})")
|
381
395
|
end
|
382
|
-
|
383
|
-
sig { params(gem_names: T::Array[String], gem_dir: String, dsl_dir: String).void }
|
384
|
-
def update_strictnesses(gem_names, gem_dir: DEFAULT_GEM_DIR, dsl_dir: DEFAULT_DSL_DIR)
|
385
|
-
return unless File.directory?(dsl_dir)
|
386
|
-
|
387
|
-
error_url_base = Spoom::Sorbet::Errors::DEFAULT_ERROR_URL_BASE
|
388
|
-
|
389
|
-
say("Typechecking RBI files... ")
|
390
|
-
res = sorbet(
|
391
|
-
"--no-config",
|
392
|
-
"--error-url-base=#{error_url_base}",
|
393
|
-
"--isolate-error-code 4010",
|
394
|
-
dsl_dir,
|
395
|
-
gem_dir
|
396
|
-
)
|
397
|
-
say(" Done", :green)
|
398
|
-
|
399
|
-
errors = Spoom::Sorbet::Errors::Parser.parse_string(res.err)
|
400
|
-
|
401
|
-
if errors.empty?
|
402
|
-
say("No error found", [:green, :bold])
|
403
|
-
return
|
404
|
-
end
|
405
|
-
|
406
|
-
files = []
|
407
|
-
|
408
|
-
errors.each do |error|
|
409
|
-
# Collect the file with error
|
410
|
-
files << error.file
|
411
|
-
error.more.each do |line|
|
412
|
-
# Also collect the conflicting definition file paths
|
413
|
-
next unless line.include?("Previous definition")
|
414
|
-
files << line.split(":").first&.strip
|
415
|
-
end
|
416
|
-
end
|
417
|
-
|
418
|
-
files
|
419
|
-
.uniq
|
420
|
-
.sort
|
421
|
-
.select do |file|
|
422
|
-
name = gem_name_from_rbi_path(file)
|
423
|
-
file.start_with?(gem_dir) && (gem_names.empty? || gem_names.include?(name))
|
424
|
-
end.each do |file|
|
425
|
-
Spoom::Sorbet::Sigils.change_sigil_in_file(file, "false")
|
426
|
-
say("\n Changed strictness of #{file} to `typed: false` (conflicting with DSL files)", [:yellow, :bold])
|
427
|
-
end
|
428
|
-
|
429
|
-
say("\n")
|
430
|
-
end
|
431
|
-
|
432
|
-
sig { params(path: String).returns(String) }
|
433
|
-
def gem_name_from_rbi_path(path)
|
434
|
-
T.must(File.basename(path, ".rbi").split("@").first)
|
435
|
-
end
|
436
396
|
end
|
437
397
|
end
|
438
398
|
end
|
@@ -74,10 +74,12 @@ module Tapioca
|
|
74
74
|
.each_line
|
75
75
|
.map do |line|
|
76
76
|
next if line.include?("<")
|
77
|
-
|
78
|
-
line.strip
|
77
|
+
|
78
|
+
line.strip
|
79
|
+
.gsub(/T\.class_of\(([:\w]+)\)/, '\1') # Turn T.class_of(Foo)::Bar into Foo::Bar
|
79
80
|
end
|
80
81
|
.compact
|
82
|
+
.sort
|
81
83
|
end
|
82
84
|
end
|
83
85
|
end
|
data/lib/tapioca/commands.rb
CHANGED
data/lib/tapioca/dsl/compiler.rb
CHANGED
@@ -17,7 +17,7 @@ module Tapioca
|
|
17
17
|
include Runtime::Reflection
|
18
18
|
extend Runtime::Reflection
|
19
19
|
|
20
|
-
ConstantType = type_member
|
20
|
+
ConstantType = type_member { { upper: Module } }
|
21
21
|
|
22
22
|
abstract!
|
23
23
|
|
@@ -54,7 +54,7 @@ module Tapioca
|
|
54
54
|
sig { returns(T::Set[Module]) }
|
55
55
|
def self.processable_constants
|
56
56
|
@processable_constants ||= T.let(
|
57
|
-
Set.new(gather_constants).
|
57
|
+
T::Set[Module].new(gather_constants).compare_by_identity,
|
58
58
|
T.nilable(T::Set[Module])
|
59
59
|
)
|
60
60
|
T.must(@processable_constants)
|
@@ -68,7 +68,7 @@ module Tapioca
|
|
68
68
|
class ActionControllerHelpers < Compiler
|
69
69
|
extend T::Sig
|
70
70
|
|
71
|
-
ConstantType = type_member
|
71
|
+
ConstantType = type_member { { fixed: T.class_of(::ActionController::Base) } }
|
72
72
|
|
73
73
|
sig { override.void }
|
74
74
|
def decorate
|
@@ -36,7 +36,7 @@ module Tapioca
|
|
36
36
|
class ActionMailer < Compiler
|
37
37
|
extend T::Sig
|
38
38
|
|
39
|
-
ConstantType = type_member
|
39
|
+
ConstantType = type_member { { fixed: T.class_of(::ActionMailer::Base) } }
|
40
40
|
|
41
41
|
sig { override.void }
|
42
42
|
def decorate
|
@@ -39,7 +39,7 @@ module Tapioca
|
|
39
39
|
class ActiveModelAttributes < Compiler
|
40
40
|
extend T::Sig
|
41
41
|
|
42
|
-
ConstantType = type_member
|
42
|
+
ConstantType = type_member { { fixed: T.all(Class, ::ActiveModel::Attributes::ClassMethods) } }
|
43
43
|
|
44
44
|
sig { override.void }
|
45
45
|
def decorate
|
@@ -60,7 +60,7 @@ module Tapioca
|
|
60
60
|
class ActiveModelSecurePassword < Compiler
|
61
61
|
extend T::Sig
|
62
62
|
|
63
|
-
ConstantType = type_member
|
63
|
+
ConstantType = type_member { { fixed: T.all(Class, ::ActiveModel::SecurePassword::ClassMethods) } }
|
64
64
|
|
65
65
|
sig { override.void }
|
66
66
|
def decorate
|
@@ -101,7 +101,7 @@ module Tapioca
|
|
101
101
|
extend T::Sig
|
102
102
|
include Helpers::ActiveRecordConstantsHelper
|
103
103
|
|
104
|
-
ConstantType = type_member
|
104
|
+
ConstantType = type_member { { fixed: T.class_of(ActiveRecord::Base) } }
|
105
105
|
|
106
106
|
sig { override.void }
|
107
107
|
def decorate
|
@@ -58,7 +58,7 @@ module Tapioca
|
|
58
58
|
class ActiveRecordEnum < Compiler
|
59
59
|
extend T::Sig
|
60
60
|
|
61
|
-
ConstantType = type_member
|
61
|
+
ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
|
62
62
|
|
63
63
|
sig { override.void }
|
64
64
|
def decorate
|
@@ -38,7 +38,7 @@ module Tapioca
|
|
38
38
|
class ActiveRecordFixtures < Compiler
|
39
39
|
extend T::Sig
|
40
40
|
|
41
|
-
ConstantType = type_member
|
41
|
+
ConstantType = type_member { { fixed: T.class_of(ActiveSupport::TestCase) } }
|
42
42
|
|
43
43
|
sig { override.void }
|
44
44
|
def decorate
|
@@ -60,6 +60,8 @@ module Tapioca
|
|
60
60
|
|
61
61
|
sig { override.returns(T::Enumerable[Module]) }
|
62
62
|
def self.gather_constants
|
63
|
+
return [] unless Rails.application
|
64
|
+
|
63
65
|
[ActiveSupport::TestCase]
|
64
66
|
end
|
65
67
|
|
@@ -118,7 +118,7 @@ module Tapioca
|
|
118
118
|
# sig { returns(T::Array[::Post]) }
|
119
119
|
# def to_ary; end
|
120
120
|
#
|
121
|
-
# Elem = type_member
|
121
|
+
# Elem = type_member { { fixed: ::Post } }
|
122
122
|
# end
|
123
123
|
#
|
124
124
|
# class PrivateCollectionProxy < ::ActiveRecord::Associations::CollectionProxy
|
@@ -141,7 +141,7 @@ module Tapioca
|
|
141
141
|
# sig { returns(T::Array[::Post]) }
|
142
142
|
# def to_ary; end
|
143
143
|
#
|
144
|
-
# Elem = type_member
|
144
|
+
# Elem = type_member { { fixed: ::Post } }
|
145
145
|
# end
|
146
146
|
# end
|
147
147
|
# ~~~
|
@@ -150,7 +150,7 @@ module Tapioca
|
|
150
150
|
include Helpers::ActiveRecordConstantsHelper
|
151
151
|
include SorbetHelper
|
152
152
|
|
153
|
-
ConstantType = type_member
|
153
|
+
ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
|
154
154
|
|
155
155
|
sig { override.void }
|
156
156
|
def decorate
|
@@ -253,7 +253,7 @@ module Tapioca
|
|
253
253
|
model.create_class(RelationClassName, superclass_name: superclass) do |klass|
|
254
254
|
klass.create_include(CommonRelationMethodsModuleName)
|
255
255
|
klass.create_include(RelationMethodsModuleName)
|
256
|
-
klass.
|
256
|
+
klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
|
257
257
|
|
258
258
|
klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
|
259
259
|
end
|
@@ -269,7 +269,7 @@ module Tapioca
|
|
269
269
|
model.create_class(AssociationRelationClassName, superclass_name: superclass) do |klass|
|
270
270
|
klass.create_include(CommonRelationMethodsModuleName)
|
271
271
|
klass.create_include(AssociationRelationMethodsModuleName)
|
272
|
-
klass.
|
272
|
+
klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
|
273
273
|
|
274
274
|
klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
|
275
275
|
end
|
@@ -281,7 +281,7 @@ module Tapioca
|
|
281
281
|
def create_relation_where_chain_class(model)
|
282
282
|
model.create_class(RelationWhereChainClassName, superclass_name: RelationClassName) do |klass|
|
283
283
|
create_where_chain_methods(klass, RelationClassName)
|
284
|
-
klass.
|
284
|
+
klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
|
285
285
|
end
|
286
286
|
end
|
287
287
|
|
@@ -292,7 +292,7 @@ module Tapioca
|
|
292
292
|
superclass_name: AssociationRelationClassName
|
293
293
|
) do |klass|
|
294
294
|
create_where_chain_methods(klass, AssociationRelationClassName)
|
295
|
-
klass.
|
295
|
+
klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
|
296
296
|
end
|
297
297
|
end
|
298
298
|
|
@@ -329,7 +329,7 @@ module Tapioca
|
|
329
329
|
model.create_class(AssociationsCollectionProxyClassName, superclass_name: superclass) do |klass|
|
330
330
|
klass.create_include(CommonRelationMethodsModuleName)
|
331
331
|
klass.create_include(AssociationRelationMethodsModuleName)
|
332
|
-
klass.
|
332
|
+
klass.create_type_variable("Elem", type: "type_member", fixed: constant_name)
|
333
333
|
|
334
334
|
klass.create_method("to_ary", return_type: "T::Array[#{constant_name}]")
|
335
335
|
create_collection_proxy_methods(klass)
|
@@ -46,7 +46,7 @@ module Tapioca
|
|
46
46
|
extend T::Sig
|
47
47
|
include Helpers::ActiveRecordConstantsHelper
|
48
48
|
|
49
|
-
ConstantType = type_member
|
49
|
+
ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
|
50
50
|
|
51
51
|
sig { override.void }
|
52
52
|
def decorate
|
@@ -90,7 +90,7 @@ module Tapioca
|
|
90
90
|
class ActiveRecordTypedStore < Compiler
|
91
91
|
extend T::Sig
|
92
92
|
|
93
|
-
ConstantType = type_member
|
93
|
+
ConstantType = type_member { { fixed: T.class_of(::ActiveRecord::Base) } }
|
94
94
|
|
95
95
|
sig { override.void }
|
96
96
|
def decorate
|
@@ -61,7 +61,7 @@ module Tapioca
|
|
61
61
|
class ActiveResource < Compiler
|
62
62
|
extend T::Sig
|
63
63
|
|
64
|
-
ConstantType = type_member
|
64
|
+
ConstantType = type_member { { fixed: T.class_of(::ActiveResource::Base) } }
|
65
65
|
|
66
66
|
sig { override.void }
|
67
67
|
def decorate
|