tapioca 0.16.11 → 0.17.0
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 +4 -4
- data/lib/ruby_lsp/tapioca/addon.rb +23 -19
- data/lib/ruby_lsp/tapioca/run_gem_rbi_check.rb +20 -20
- data/lib/tapioca/bundler_ext/auto_require_hook.rb +5 -10
- data/lib/tapioca/commands/abstract_dsl.rb +26 -59
- data/lib/tapioca/commands/abstract_gem.rb +23 -43
- data/lib/tapioca/commands/annotations.rb +27 -33
- data/lib/tapioca/commands/check_shims.rb +4 -13
- data/lib/tapioca/commands/command.rb +8 -20
- data/lib/tapioca/commands/command_without_tracker.rb +1 -1
- data/lib/tapioca/commands/configure.rb +11 -16
- data/lib/tapioca/commands/dsl_compiler_list.rb +2 -1
- data/lib/tapioca/commands/dsl_generate.rb +2 -1
- data/lib/tapioca/commands/dsl_verify.rb +2 -1
- data/lib/tapioca/commands/gem_generate.rb +4 -8
- data/lib/tapioca/commands/gem_sync.rb +2 -1
- data/lib/tapioca/commands/gem_verify.rb +3 -2
- data/lib/tapioca/commands/require.rb +3 -7
- data/lib/tapioca/commands/todo.rb +6 -10
- data/lib/tapioca/dsl/compiler.rb +28 -53
- data/lib/tapioca/dsl/compilers/aasm.rb +31 -41
- data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +7 -5
- data/lib/tapioca/dsl/compilers/action_mailer.rb +5 -3
- data/lib/tapioca/dsl/compilers/action_text.rb +5 -3
- data/lib/tapioca/dsl/compilers/active_job.rb +5 -8
- data/lib/tapioca/dsl/compilers/active_model_attributes.rb +9 -7
- data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +4 -2
- data/lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb +4 -2
- data/lib/tapioca/dsl/compilers/active_record_associations.rb +16 -42
- data/lib/tapioca/dsl/compilers/active_record_columns.rb +19 -24
- data/lib/tapioca/dsl/compilers/active_record_delegated_types.rb +7 -5
- data/lib/tapioca/dsl/compilers/active_record_enum.rb +6 -4
- data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +53 -61
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +86 -119
- data/lib/tapioca/dsl/compilers/active_record_scope.rb +7 -11
- data/lib/tapioca/dsl/compilers/active_record_secure_token.rb +4 -2
- data/lib/tapioca/dsl/compilers/active_record_store.rb +4 -2
- data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +18 -26
- data/lib/tapioca/dsl/compilers/active_resource.rb +18 -19
- data/lib/tapioca/dsl/compilers/active_storage.rb +5 -5
- data/lib/tapioca/dsl/compilers/active_support_concern.rb +8 -6
- data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +7 -5
- data/lib/tapioca/dsl/compilers/active_support_time_ext.rb +4 -2
- data/lib/tapioca/dsl/compilers/config.rb +4 -2
- data/lib/tapioca/dsl/compilers/frozen_record.rb +6 -9
- data/lib/tapioca/dsl/compilers/graphql_input_object.rb +8 -8
- data/lib/tapioca/dsl/compilers/graphql_mutation.rb +5 -8
- data/lib/tapioca/dsl/compilers/identity_cache.rb +10 -37
- data/lib/tapioca/dsl/compilers/json_api_client_resource.rb +8 -16
- data/lib/tapioca/dsl/compilers/kredis.rb +6 -4
- data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +4 -2
- data/lib/tapioca/dsl/compilers/protobuf.rb +12 -24
- data/lib/tapioca/dsl/compilers/rails_generators.rb +8 -9
- data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +22 -11
- data/lib/tapioca/dsl/compilers/smart_properties.rb +11 -20
- data/lib/tapioca/dsl/compilers/state_machines.rb +14 -24
- data/lib/tapioca/dsl/compilers/url_helpers.rb +9 -7
- data/lib/tapioca/dsl/compilers.rb +4 -7
- data/lib/tapioca/dsl/helpers/active_model_type_helper.rb +13 -16
- data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +13 -28
- data/lib/tapioca/dsl/helpers/active_record_constants_helper.rb +19 -15
- data/lib/tapioca/dsl/helpers/graphql_type_helper.rb +5 -24
- data/lib/tapioca/dsl/pipeline.rb +23 -55
- data/lib/tapioca/executor.rb +6 -12
- data/lib/tapioca/gem/events.rb +22 -28
- data/lib/tapioca/gem/listeners/base.rb +6 -6
- data/lib/tapioca/gem/listeners/dynamic_mixins.rb +4 -2
- data/lib/tapioca/gem/listeners/foreign_constants.rb +5 -7
- data/lib/tapioca/gem/listeners/methods.rb +15 -34
- data/lib/tapioca/gem/listeners/mixins.rb +6 -18
- data/lib/tapioca/gem/listeners/remove_empty_payload_scopes.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_enums.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_helpers.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_props.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_required_ancestors.rb +4 -2
- data/lib/tapioca/gem/listeners/sorbet_signatures.rb +7 -5
- data/lib/tapioca/gem/listeners/sorbet_type_variables.rb +6 -4
- data/lib/tapioca/gem/listeners/source_location.rb +7 -4
- data/lib/tapioca/gem/listeners/subconstants.rb +4 -2
- data/lib/tapioca/gem/listeners/yard_doc.rb +23 -22
- data/lib/tapioca/gem/pipeline.rb +57 -72
- data/lib/tapioca/gem_info.rb +1 -1
- data/lib/tapioca/gemfile.rb +64 -73
- data/lib/tapioca/helpers/cli_helper.rb +3 -3
- data/lib/tapioca/helpers/config_helper.rb +15 -24
- data/lib/tapioca/helpers/env_helper.rb +1 -1
- data/lib/tapioca/helpers/gem_helper.rb +5 -5
- data/lib/tapioca/helpers/git_attributes.rb +3 -3
- data/lib/tapioca/helpers/rbi_files_helper.rb +73 -67
- data/lib/tapioca/helpers/rbi_helper.rb +14 -22
- data/lib/tapioca/helpers/sorbet_helper.rb +9 -18
- data/lib/tapioca/helpers/source_uri.rb +15 -25
- data/lib/tapioca/helpers/test/content.rb +6 -6
- data/lib/tapioca/helpers/test/dsl_compiler.rb +19 -29
- data/lib/tapioca/helpers/test/isolation.rb +4 -4
- data/lib/tapioca/helpers/test/template.rb +5 -7
- data/lib/tapioca/internal.rb +5 -1
- data/lib/tapioca/loaders/dsl.rb +11 -19
- data/lib/tapioca/loaders/gem.rb +6 -21
- data/lib/tapioca/loaders/loader.rb +15 -27
- data/lib/tapioca/rbi_ext/model.rb +12 -37
- data/lib/tapioca/rbi_formatter.rb +10 -19
- data/lib/tapioca/rbs/rewriter.rb +55 -0
- data/lib/tapioca/repo_index.rb +7 -7
- data/lib/tapioca/runtime/attached_class_of_32.rb +1 -1
- data/lib/tapioca/runtime/attached_class_of_legacy.rb +1 -1
- data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +23 -23
- data/lib/tapioca/runtime/generic_type_registry.rb +13 -23
- data/lib/tapioca/runtime/reflection.rb +48 -56
- data/lib/tapioca/runtime/trackers/autoload.rb +4 -8
- data/lib/tapioca/runtime/trackers/mixin.rb +6 -10
- data/lib/tapioca/runtime/trackers/required_ancestor.rb +3 -3
- data/lib/tapioca/runtime/trackers/tracker.rb +2 -2
- data/lib/tapioca/runtime/trackers.rb +4 -8
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +9 -15
- data/lib/tapioca/sorbet_ext/name_patch.rb +1 -1
- data/lib/tapioca/sorbet_ext/proc_bind_patch.rb +1 -1
- data/lib/tapioca/static/requires_compiler.rb +6 -6
- data/lib/tapioca/static/symbol_loader.rb +14 -16
- data/lib/tapioca/static/symbol_table_parser.rb +8 -8
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +22 -29
- metadata +25 -10
@@ -9,7 +9,7 @@ module Tapioca
|
|
9
9
|
requires_ancestor { Thor::Shell }
|
10
10
|
requires_ancestor { SorbetHelper }
|
11
11
|
|
12
|
-
|
12
|
+
#: (RBI::Index index, String kind, String file) -> void
|
13
13
|
def index_rbi(index, kind, file)
|
14
14
|
return unless File.exist?(file)
|
15
15
|
|
@@ -21,7 +21,7 @@ module Tapioca
|
|
21
21
|
say("(#{time.round(2)}s)")
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
#: (RBI::Index index, String kind, String dir, number_of_workers: Integer?) -> void
|
25
25
|
def index_rbis(index, kind, dir, number_of_workers:)
|
26
26
|
return unless Dir.exist?(dir) && !Dir.empty?(dir)
|
27
27
|
|
@@ -38,13 +38,7 @@ module Tapioca
|
|
38
38
|
say("(#{time.round(2)}s)")
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
params(
|
43
|
-
index: RBI::Index,
|
44
|
-
shim_rbi_dir: String,
|
45
|
-
todo_rbi_file: String,
|
46
|
-
).returns(T::Hash[String, T::Array[RBI::Node]])
|
47
|
-
end
|
41
|
+
#: (RBI::Index index, shim_rbi_dir: String, todo_rbi_file: String) -> Hash[String, Array[RBI::Node]]
|
48
42
|
def duplicated_nodes_from_index(index, shim_rbi_dir:, todo_rbi_file:)
|
49
43
|
duplicates = {}
|
50
44
|
say("Looking for duplicates... ")
|
@@ -61,7 +55,7 @@ module Tapioca
|
|
61
55
|
duplicates
|
62
56
|
end
|
63
57
|
|
64
|
-
|
58
|
+
#: (RBI::Loc loc, path_prefix: String?) -> String
|
65
59
|
def location_to_payload_url(loc, path_prefix:)
|
66
60
|
return loc.to_s unless path_prefix
|
67
61
|
|
@@ -73,16 +67,7 @@ module Tapioca
|
|
73
67
|
url
|
74
68
|
end
|
75
69
|
|
76
|
-
|
77
|
-
params(
|
78
|
-
command: String,
|
79
|
-
gem_dir: String,
|
80
|
-
dsl_dir: String,
|
81
|
-
auto_strictness: T::Boolean,
|
82
|
-
gems: T::Array[Gemfile::GemSpec],
|
83
|
-
compilers: T::Enumerable[T.class_of(Dsl::Compiler)],
|
84
|
-
).void
|
85
|
-
end
|
70
|
+
#: (command: String, gem_dir: String, dsl_dir: String, auto_strictness: bool, ?gems: Array[Gemfile::GemSpec], ?compilers: T::Enumerable[singleton(Dsl::Compiler)]) -> void
|
86
71
|
def validate_rbi_files(command:, gem_dir:, dsl_dir:, auto_strictness:, gems: [], compilers: [])
|
87
72
|
error_url_base = Spoom::Sorbet::Errors::DEFAULT_ERROR_URL_BASE
|
88
73
|
|
@@ -151,7 +136,7 @@ module Tapioca
|
|
151
136
|
|
152
137
|
private
|
153
138
|
|
154
|
-
|
139
|
+
#: (RBI::Index index, Array[String] files, number_of_workers: Integer?) -> void
|
155
140
|
def parse_and_index_files(index, files, number_of_workers:)
|
156
141
|
executor = Executor.new(files, number_of_workers: number_of_workers)
|
157
142
|
|
@@ -167,64 +152,100 @@ module Tapioca
|
|
167
152
|
index.visit_all(trees)
|
168
153
|
end
|
169
154
|
|
170
|
-
|
155
|
+
# Do the list of `nodes` sharing the same name have duplicates?
|
156
|
+
#: (Array[RBI::Node] nodes, shim_rbi_dir: String, todo_rbi_file: String) -> bool
|
171
157
|
def shims_or_todos_have_duplicates?(nodes, shim_rbi_dir:, todo_rbi_file:)
|
158
|
+
# If there is only one node, there are no duplicates
|
172
159
|
return false if nodes.size == 1
|
173
160
|
|
161
|
+
# Extract the nodes from the sorbet/rbi/shims/ directory and the todo.rbi file
|
174
162
|
shims_or_todos = extract_shims_and_todos(nodes, shim_rbi_dir: shim_rbi_dir, todo_rbi_file: todo_rbi_file)
|
175
163
|
return false if shims_or_todos.empty?
|
176
164
|
|
177
|
-
|
178
|
-
|
165
|
+
# First let's look into scopes (classes, modules, sclass) for duplicates
|
166
|
+
has_duplicated_scopes?(nodes, shims_or_todos) ||
|
167
|
+
# Then let's look into mixins
|
168
|
+
has_duplicated_mixins?(shims_or_todos) ||
|
169
|
+
# Finally, let's compare the methods and attributes with the same name
|
170
|
+
has_duplicated_methods_and_attrs?(nodes, shims_or_todos)
|
171
|
+
end
|
172
|
+
|
173
|
+
#: (Array[RBI::Node], Array[RBI::Node]) -> bool
|
174
|
+
def has_duplicated_scopes?(all_nodes, shims_or_todos)
|
175
|
+
shims_or_todos_scopes = shims_or_todos.grep(RBI::Scope)
|
176
|
+
return false if shims_or_todos_scopes.empty?
|
177
|
+
|
178
|
+
# Extract the empty scopes from the shims or todos
|
179
|
+
# We do not care about non-empty scopes because they hold definitions that we will check against Tapioca's
|
180
|
+
# generated RBI files in another iteration.
|
181
|
+
shims_or_todos_empty_scopes = shims_or_todos_scopes.select(&:empty?)
|
182
|
+
|
183
|
+
# Extract the nodes that are not shims or todos (basically the nodes from the RBI files generated by Tapioca)
|
184
|
+
not_shims_or_todos = all_nodes - shims_or_todos
|
179
185
|
|
180
|
-
|
181
|
-
shims_or_todos_empty_scopes.select! do |scope|
|
186
|
+
shims_or_todos_empty_scopes.any? do |scope|
|
182
187
|
# Empty modules are always duplicates
|
183
|
-
|
188
|
+
break true unless scope.is_a?(RBI::Class)
|
184
189
|
|
185
190
|
# Empty classes without parents are also duplicates
|
186
191
|
parent_name = scope.superclass_name
|
187
|
-
|
192
|
+
break true unless parent_name
|
188
193
|
|
189
194
|
# Empty classes that are not redefining the parent are also duplicates
|
190
|
-
not_shims_or_todos.any?
|
195
|
+
break true if not_shims_or_todos.any? do |node|
|
196
|
+
node.is_a?(RBI::Class) && node.superclass_name == parent_name
|
197
|
+
end
|
191
198
|
end
|
192
|
-
|
199
|
+
end
|
200
|
+
|
201
|
+
#: (Array[RBI::Node] shims_or_todos) -> bool
|
202
|
+
def has_duplicated_mixins?(shims_or_todos)
|
203
|
+
# Don't forget `shims_or_todos` is a list of nodes with the same qualified name, so if we find two mixins of the
|
204
|
+
# same name, they _are_ about the same thing, like two `include(A)` or two `requires_ancestor(A)` so this is a
|
205
|
+
# duplicate
|
206
|
+
shims_or_todos.any? { |node| node.is_a?(RBI::Mixin) || node.is_a?(RBI::RequiresAncestor) }
|
207
|
+
end
|
193
208
|
|
194
|
-
|
195
|
-
|
209
|
+
#: (Array[RBI::Node] nodes, Array[RBI::Node] shims_or_todos) -> bool
|
210
|
+
def has_duplicated_methods_and_attrs?(nodes, shims_or_todos)
|
211
|
+
shims_or_todos_props = extract_methods_and_attrs(shims_or_todos)
|
212
|
+
if shims_or_todos_props.any?
|
213
|
+
shims_or_todos_props.each do |shim_or_todo_prop|
|
214
|
+
other_nodes = extract_methods_and_attrs(nodes) - [shim_or_todo_prop]
|
196
215
|
|
197
|
-
|
198
|
-
|
216
|
+
if shim_or_todo_prop.sigs.empty?
|
217
|
+
# If the node doesn't have a signature and is an attribute accessor, we have a duplicate
|
218
|
+
return true if shim_or_todo_prop.is_a?(RBI::Attr)
|
199
219
|
|
200
|
-
|
201
|
-
shims_or_todos_with_sigs.each do |shim_or_todo|
|
202
|
-
shims_or_todos_sigs = shim_or_todo.sigs
|
220
|
+
# Now we know it's a method
|
203
221
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
222
|
+
# If the node has no parameters and we compare it against an attribute of the same name, it's a duplicate
|
223
|
+
return true if shim_or_todo_prop.params.empty? && other_nodes.grep(RBI::Attr).any?
|
224
|
+
|
225
|
+
# If the node has parameters, we compare them against all the other methods
|
226
|
+
# If at least one of them has the same parameters, it's a duplicate
|
227
|
+
return true if other_nodes.grep(RBI::Method).any? { |other| shim_or_todo_prop.params == other.params }
|
228
|
+
end
|
208
229
|
|
209
|
-
|
230
|
+
# We compare the shim or todo prop with all the other props of the same name
|
231
|
+
other_nodes.each do |node|
|
232
|
+
# Another prop has the same sig, we have a duplicate
|
233
|
+
return true if shim_or_todo_prop.sigs.any? { |sig| node.sigs.include?(sig) }
|
234
|
+
end
|
235
|
+
end
|
210
236
|
end
|
211
237
|
|
212
|
-
|
238
|
+
false
|
213
239
|
end
|
214
240
|
|
215
|
-
|
241
|
+
#: (Array[RBI::Node] nodes, shim_rbi_dir: String, todo_rbi_file: String) -> Array[RBI::Node]
|
216
242
|
def extract_shims_and_todos(nodes, shim_rbi_dir:, todo_rbi_file:)
|
217
243
|
nodes.select do |node|
|
218
244
|
node.loc&.file&.start_with?(shim_rbi_dir) || node.loc&.file == todo_rbi_file
|
219
245
|
end
|
220
246
|
end
|
221
247
|
|
222
|
-
|
223
|
-
def extract_empty_scopes(nodes)
|
224
|
-
T.cast(nodes.select { |node| node.is_a?(RBI::Scope) && node.empty? }, T::Array[RBI::Scope])
|
225
|
-
end
|
226
|
-
|
227
|
-
sig { params(nodes: T::Array[RBI::Node]).returns(T::Array[T.any(RBI::Method, RBI::Attr)]) }
|
248
|
+
#: (Array[RBI::Node] nodes) -> Array[(RBI::Method | RBI::Attr)]
|
228
249
|
def extract_methods_and_attrs(nodes)
|
229
250
|
T.cast(
|
230
251
|
nodes.select do |node|
|
@@ -234,22 +255,7 @@ module Tapioca
|
|
234
255
|
)
|
235
256
|
end
|
236
257
|
|
237
|
-
|
238
|
-
def extract_mixins(nodes)
|
239
|
-
T.cast(
|
240
|
-
nodes.select do |node|
|
241
|
-
node.is_a?(RBI::Mixin) || node.is_a?(RBI::RequiresAncestor)
|
242
|
-
end,
|
243
|
-
T::Array[T.all(RBI::Mixin, RBI::RequiresAncestor)],
|
244
|
-
)
|
245
|
-
end
|
246
|
-
|
247
|
-
sig { params(nodes: T::Array[T.any(RBI::Method, RBI::Attr)]).returns(T::Array[T.any(RBI::Method, RBI::Attr)]) }
|
248
|
-
def extract_nodes_with_sigs(nodes)
|
249
|
-
nodes.reject { |node| node.sigs.empty? }
|
250
|
-
end
|
251
|
-
|
252
|
-
sig { params(errors: T::Array[Spoom::Sorbet::Errors::Error], gem_dir: String).void }
|
258
|
+
#: (Array[Spoom::Sorbet::Errors::Error] errors, String gem_dir) -> void
|
253
259
|
def update_gem_rbis_strictnesses(errors, gem_dir)
|
254
260
|
files = []
|
255
261
|
|
@@ -276,7 +282,7 @@ module Tapioca
|
|
276
282
|
say("\n")
|
277
283
|
end
|
278
284
|
|
279
|
-
|
285
|
+
#: (String path) -> String
|
280
286
|
def gem_name_from_rbi_path(path)
|
281
287
|
T.must(File.basename(path, ".rbi").split("@").first)
|
282
288
|
end
|
@@ -11,15 +11,7 @@ module Tapioca
|
|
11
11
|
class << self
|
12
12
|
extend T::Sig
|
13
13
|
|
14
|
-
|
15
|
-
params(
|
16
|
-
type: String,
|
17
|
-
variance: Symbol,
|
18
|
-
fixed: T.nilable(String),
|
19
|
-
upper: T.nilable(String),
|
20
|
-
lower: T.nilable(String),
|
21
|
-
).returns(String)
|
22
|
-
end
|
14
|
+
#: (String type, Symbol variance, String? fixed, String? upper, String? lower) -> String
|
23
15
|
def serialize_type_variable(type, variance, fixed, upper, lower)
|
24
16
|
variance = nil if variance == :invariant
|
25
17
|
|
@@ -38,47 +30,47 @@ module Tapioca
|
|
38
30
|
end
|
39
31
|
end
|
40
32
|
|
41
|
-
|
33
|
+
#: (String name, type: String) -> RBI::TypedParam
|
42
34
|
def create_param(name, type:)
|
43
35
|
create_typed_param(RBI::ReqParam.new(name), type)
|
44
36
|
end
|
45
37
|
|
46
|
-
|
38
|
+
#: (String name, type: String, default: String) -> RBI::TypedParam
|
47
39
|
def create_opt_param(name, type:, default:)
|
48
40
|
create_typed_param(RBI::OptParam.new(name, default), type)
|
49
41
|
end
|
50
42
|
|
51
|
-
|
43
|
+
#: (String name, type: String) -> RBI::TypedParam
|
52
44
|
def create_rest_param(name, type:)
|
53
45
|
create_typed_param(RBI::RestParam.new(name), type)
|
54
46
|
end
|
55
47
|
|
56
|
-
|
48
|
+
#: (String name, type: String) -> RBI::TypedParam
|
57
49
|
def create_kw_param(name, type:)
|
58
50
|
create_typed_param(RBI::KwParam.new(name), type)
|
59
51
|
end
|
60
52
|
|
61
|
-
|
53
|
+
#: (String name, type: String, default: String) -> RBI::TypedParam
|
62
54
|
def create_kw_opt_param(name, type:, default:)
|
63
55
|
create_typed_param(RBI::KwOptParam.new(name, default), type)
|
64
56
|
end
|
65
57
|
|
66
|
-
|
58
|
+
#: (String name, type: String) -> RBI::TypedParam
|
67
59
|
def create_kw_rest_param(name, type:)
|
68
60
|
create_typed_param(RBI::KwRestParam.new(name), type)
|
69
61
|
end
|
70
62
|
|
71
|
-
|
63
|
+
#: (String name, type: String) -> RBI::TypedParam
|
72
64
|
def create_block_param(name, type:)
|
73
65
|
create_typed_param(RBI::BlockParam.new(name), type)
|
74
66
|
end
|
75
67
|
|
76
|
-
|
68
|
+
#: (RBI::Param param, String type) -> RBI::TypedParam
|
77
69
|
def create_typed_param(param, type)
|
78
70
|
RBI::TypedParam.new(param: param, type: sanitize_signature_types(type))
|
79
71
|
end
|
80
72
|
|
81
|
-
|
73
|
+
#: (String sig_string) -> String
|
82
74
|
def sanitize_signature_types(sig_string)
|
83
75
|
sig_string
|
84
76
|
.gsub(".returns(<VOID>)", ".void")
|
@@ -87,7 +79,7 @@ module Tapioca
|
|
87
79
|
.gsub(".params()", "")
|
88
80
|
end
|
89
81
|
|
90
|
-
|
82
|
+
#: (String type) -> String
|
91
83
|
def as_nilable_type(type)
|
92
84
|
if type.start_with?("T.nilable(", "::T.nilable(") || type == "T.untyped" || type == "::T.untyped"
|
93
85
|
type
|
@@ -96,7 +88,7 @@ module Tapioca
|
|
96
88
|
end
|
97
89
|
end
|
98
90
|
|
99
|
-
|
91
|
+
#: (String type) -> String
|
100
92
|
def as_non_nilable_type(type)
|
101
93
|
if type.match(/\A(?:::)?T.nilable\((.+)\)\z/)
|
102
94
|
T.must(::Regexp.last_match(1))
|
@@ -105,12 +97,12 @@ module Tapioca
|
|
105
97
|
end
|
106
98
|
end
|
107
99
|
|
108
|
-
|
100
|
+
#: (String name) -> bool
|
109
101
|
def valid_method_name?(name)
|
110
102
|
Prism.parse_success?("def self.#{name}(a); end")
|
111
103
|
end
|
112
104
|
|
113
|
-
|
105
|
+
#: (String name) -> bool
|
114
106
|
def valid_parameter_name?(name)
|
115
107
|
Prism.parse_success?("def sentinel_method_name(#{name}:); end")
|
116
108
|
end
|
@@ -5,42 +5,33 @@ module Tapioca
|
|
5
5
|
module SorbetHelper
|
6
6
|
extend T::Sig
|
7
7
|
|
8
|
-
SORBET_GEM_SPEC =
|
9
|
-
::Gem::Specification.find_by_name("sorbet-static"),
|
10
|
-
::Gem::Specification,
|
11
|
-
)
|
8
|
+
SORBET_GEM_SPEC = ::Gem::Specification.find_by_name("sorbet-static") #: ::Gem::Specification
|
12
9
|
|
13
|
-
SORBET_BIN =
|
14
|
-
Pathname.new(SORBET_GEM_SPEC.full_gem_path) / "libexec" / "sorbet",
|
15
|
-
Pathname,
|
16
|
-
)
|
10
|
+
SORBET_BIN = Pathname.new(SORBET_GEM_SPEC.full_gem_path) / "libexec" / "sorbet" #: Pathname
|
17
11
|
|
18
12
|
SORBET_EXE_PATH_ENV_VAR = "TAPIOCA_SORBET_EXE"
|
19
13
|
|
20
14
|
SORBET_PAYLOAD_URL = "https://github.com/sorbet/sorbet/tree/master/rbi"
|
21
15
|
|
22
|
-
SPOOM_CONTEXT =
|
16
|
+
SPOOM_CONTEXT = Spoom::Context.new(".") #: Spoom::Context
|
23
17
|
|
24
|
-
FEATURE_REQUIREMENTS =
|
25
|
-
|
26
|
-
|
27
|
-
}.freeze,
|
28
|
-
T::Hash[Symbol, ::Gem::Requirement],
|
29
|
-
)
|
18
|
+
FEATURE_REQUIREMENTS = {
|
19
|
+
# feature_name: ::Gem::Requirement.new(">= ___"), # https://github.com/sorbet/sorbet/pull/___
|
20
|
+
}.freeze #: Hash[Symbol, ::Gem::Requirement]
|
30
21
|
|
31
|
-
|
22
|
+
#: (*String sorbet_args) -> Spoom::ExecResult
|
32
23
|
def sorbet(*sorbet_args)
|
33
24
|
SPOOM_CONTEXT.srb(sorbet_args.join(" "), sorbet_bin: sorbet_path)
|
34
25
|
end
|
35
26
|
|
36
|
-
|
27
|
+
#: -> String
|
37
28
|
def sorbet_path
|
38
29
|
sorbet_path = ENV.fetch(SORBET_EXE_PATH_ENV_VAR, SORBET_BIN)
|
39
30
|
sorbet_path = SORBET_BIN if sorbet_path.empty?
|
40
31
|
sorbet_path.to_s.shellescape
|
41
32
|
end
|
42
33
|
|
43
|
-
|
34
|
+
#: (Symbol feature, ?version: ::Gem::Version?) -> bool
|
44
35
|
def sorbet_supports?(feature, version: nil)
|
45
36
|
version = SORBET_GEM_SPEC.version unless version
|
46
37
|
requirement = FEATURE_REQUIREMENTS[feature]
|
@@ -7,38 +7,28 @@ module Tapioca
|
|
7
7
|
class SourceURI < URI::File
|
8
8
|
extend T::Sig
|
9
9
|
|
10
|
-
COMPONENT =
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
].freeze,
|
18
|
-
T::Array[Symbol],
|
19
|
-
)
|
10
|
+
COMPONENT = [
|
11
|
+
:scheme,
|
12
|
+
:gem_name,
|
13
|
+
:gem_version,
|
14
|
+
:path,
|
15
|
+
:line_number,
|
16
|
+
].freeze #: Array[Symbol]
|
20
17
|
|
21
18
|
# `uri` for Ruby 3.4 switched the default parser from RFC2396 to RFC3986. The new parser emits a deprecation
|
22
19
|
# warning on a few methods and delegates them to RFC2396, namely `extract`/`make_regexp`/`escape`/`unescape`.
|
23
20
|
# On earlier versions of the uri gem, the RFC2396_PARSER constant doesn't exist, so it needs some special
|
24
21
|
# handling to select a parser that doesn't emit deprecations. While it was backported to Ruby 3.1, users may
|
25
22
|
# have the uri gem in their own bundle and thus not use a compatible version.
|
26
|
-
PARSER =
|
23
|
+
PARSER = const_defined?(:RFC2396_PARSER) ? RFC2396_PARSER : DEFAULT_PARSER #: RFC2396_Parser
|
27
24
|
|
28
|
-
|
25
|
+
#: String?
|
29
26
|
attr_reader :gem_version
|
30
27
|
|
31
28
|
class << self
|
32
29
|
extend T::Sig
|
33
30
|
|
34
|
-
|
35
|
-
params(
|
36
|
-
gem_name: String,
|
37
|
-
gem_version: T.nilable(String),
|
38
|
-
path: String,
|
39
|
-
line_number: T.nilable(String),
|
40
|
-
).returns(T.attached_class)
|
41
|
-
end
|
31
|
+
#: (gem_name: String, gem_version: String?, path: String, line_number: String?) -> instance
|
42
32
|
def build(gem_name:, gem_version:, path:, line_number:)
|
43
33
|
super(
|
44
34
|
{
|
@@ -51,24 +41,24 @@ module Tapioca
|
|
51
41
|
end
|
52
42
|
end
|
53
43
|
|
54
|
-
|
44
|
+
#: -> String?
|
55
45
|
def gem_name
|
56
46
|
host
|
57
47
|
end
|
58
48
|
|
59
|
-
|
49
|
+
#: -> String?
|
60
50
|
def line_number
|
61
51
|
fragment
|
62
52
|
end
|
63
53
|
|
64
|
-
|
54
|
+
#: (String? v) -> void
|
65
55
|
def set_path(v) # rubocop:disable Naming/AccessorMethodName
|
66
56
|
return if v.nil?
|
67
57
|
|
68
58
|
@gem_version, @path = v.split("/", 2)
|
69
59
|
end
|
70
60
|
|
71
|
-
|
61
|
+
#: (String? v) -> bool
|
72
62
|
def check_host(v)
|
73
63
|
return true unless v
|
74
64
|
|
@@ -80,7 +70,7 @@ module Tapioca
|
|
80
70
|
true
|
81
71
|
end
|
82
72
|
|
83
|
-
|
73
|
+
#: -> String
|
84
74
|
def to_s
|
85
75
|
"source://#{gem_name}/#{gem_version}#{path}##{line_number}"
|
86
76
|
end
|
@@ -10,32 +10,32 @@ module Tapioca
|
|
10
10
|
|
11
11
|
requires_ancestor { Kernel }
|
12
12
|
|
13
|
-
|
13
|
+
#: -> void
|
14
14
|
def teardown
|
15
15
|
super
|
16
16
|
remove_tmp_path
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
#: (*String args) -> String
|
20
20
|
def tmp_path(*args)
|
21
|
-
@tmp_path =
|
21
|
+
@tmp_path = @tmp_path #: String?
|
22
22
|
@tmp_path ||= Dir.mktmpdir
|
23
23
|
T.unsafe(File).join(@tmp_path, *args)
|
24
24
|
end
|
25
25
|
|
26
|
-
|
26
|
+
#: -> void
|
27
27
|
def remove_tmp_path
|
28
28
|
FileUtils.rm_rf(tmp_path)
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
#: (String name, String content, ?require_file: bool) -> String
|
32
32
|
def add_ruby_file(name, content, require_file: true)
|
33
33
|
add_content_file(name, content).tap do |file_name|
|
34
34
|
Tapioca.silence_warnings { require(file_name) } if require_file
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
|
38
|
+
#: (String name, String content) -> String
|
39
39
|
def add_content_file(name, content)
|
40
40
|
file_name = tmp_path("lib/#{name}")
|
41
41
|
raise ArgumentError, "a file named '#{name}' was already added; cannot overwrite." if File.exist?(file_name)
|
@@ -20,37 +20,32 @@ module Tapioca
|
|
20
20
|
|
21
21
|
requires_ancestor { Kernel }
|
22
22
|
|
23
|
-
|
23
|
+
#: (singleton(Tapioca::Dsl::Compiler) compiler_class) -> void
|
24
24
|
def use_dsl_compiler(compiler_class)
|
25
|
-
@context =
|
25
|
+
@context = CompilerContext.new(compiler_class) #: CompilerContext?
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
#: (*singleton(Tapioca::Dsl::Compiler) compiler_classes) -> void
|
29
29
|
def activate_other_dsl_compilers(*compiler_classes)
|
30
30
|
context.activate_other_dsl_compilers(compiler_classes)
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
params(
|
35
|
-
constant_name: T.any(Symbol, String),
|
36
|
-
compiler_options: T::Hash[Symbol, T.untyped],
|
37
|
-
).returns(String)
|
38
|
-
end
|
33
|
+
#: ((Symbol | String) constant_name, ?compiler_options: Hash[Symbol, untyped]) -> String
|
39
34
|
def rbi_for(constant_name, compiler_options: {})
|
40
35
|
context.rbi_for(constant_name, compiler_options: compiler_options)
|
41
36
|
end
|
42
37
|
|
43
|
-
|
38
|
+
#: -> Array[String]
|
44
39
|
def gathered_constants
|
45
40
|
context.gathered_constants
|
46
41
|
end
|
47
42
|
|
48
|
-
|
43
|
+
#: -> Array[String]
|
49
44
|
def generated_errors
|
50
45
|
context.errors
|
51
46
|
end
|
52
47
|
|
53
|
-
|
48
|
+
#: -> CompilerContext
|
54
49
|
def context
|
55
50
|
raise "Please call `use_dsl_compiler` before" unless @context
|
56
51
|
|
@@ -62,41 +57,36 @@ module Tapioca
|
|
62
57
|
|
63
58
|
include SorbetHelper
|
64
59
|
|
65
|
-
|
60
|
+
#: singleton(Tapioca::Dsl::Compiler)
|
66
61
|
attr_reader :compiler_class
|
67
62
|
|
68
|
-
|
63
|
+
#: Array[singleton(Tapioca::Dsl::Compiler)]
|
69
64
|
attr_reader :other_compiler_classes
|
70
65
|
|
71
|
-
|
66
|
+
#: (singleton(Tapioca::Dsl::Compiler) compiler_class) -> void
|
72
67
|
def initialize(compiler_class)
|
73
68
|
@compiler_class = compiler_class
|
74
|
-
@other_compiler_classes =
|
75
|
-
@pipeline =
|
76
|
-
@errors =
|
69
|
+
@other_compiler_classes = [] #: Array[singleton(Tapioca::Dsl::Compiler)]
|
70
|
+
@pipeline = nil #: Tapioca::Dsl::Pipeline?
|
71
|
+
@errors = [] #: Array[String]
|
77
72
|
end
|
78
73
|
|
79
|
-
|
74
|
+
#: (Array[singleton(Tapioca::Dsl::Compiler)] compiler_classes) -> void
|
80
75
|
def activate_other_dsl_compilers(compiler_classes)
|
81
76
|
@other_compiler_classes = compiler_classes
|
82
77
|
end
|
83
78
|
|
84
|
-
|
79
|
+
#: -> Array[singleton(Tapioca::Dsl::Compiler)]
|
85
80
|
def activated_compiler_classes
|
86
81
|
[compiler_class, *other_compiler_classes]
|
87
82
|
end
|
88
83
|
|
89
|
-
|
84
|
+
#: -> Array[String]
|
90
85
|
def gathered_constants
|
91
86
|
compiler_class.processable_constants.filter_map(&:name).sort
|
92
87
|
end
|
93
88
|
|
94
|
-
|
95
|
-
params(
|
96
|
-
constant_name: T.any(Symbol, String),
|
97
|
-
compiler_options: T::Hash[Symbol, T.untyped],
|
98
|
-
).returns(String)
|
99
|
-
end
|
89
|
+
#: ((Symbol | String) constant_name, ?compiler_options: Hash[Symbol, untyped]) -> String
|
100
90
|
def rbi_for(constant_name, compiler_options: {})
|
101
91
|
# Make sure this is a constant that we can handle.
|
102
92
|
unless gathered_constants.include?(constant_name.to_s)
|
@@ -131,14 +121,14 @@ module Tapioca
|
|
131
121
|
rbi
|
132
122
|
end
|
133
123
|
|
134
|
-
|
124
|
+
#: -> Array[String]
|
135
125
|
def errors
|
136
126
|
pipeline.errors
|
137
127
|
end
|
138
128
|
|
139
129
|
private
|
140
130
|
|
141
|
-
|
131
|
+
#: -> Tapioca::Dsl::Pipeline
|
142
132
|
def pipeline
|
143
133
|
@pipeline ||= Tapioca::Dsl::Pipeline.new(
|
144
134
|
requested_constants: [],
|
@@ -13,7 +13,7 @@ module Tapioca
|
|
13
13
|
class << self
|
14
14
|
extend T::Sig
|
15
15
|
|
16
|
-
|
16
|
+
#: -> bool
|
17
17
|
def forking_env?
|
18
18
|
!ENV["NO_FORK"] && Process.respond_to?(:fork)
|
19
19
|
end
|
@@ -33,7 +33,7 @@ module Tapioca
|
|
33
33
|
|
34
34
|
requires_ancestor { Kernel }
|
35
35
|
|
36
|
-
|
36
|
+
#: ?{ (?) -> untyped } -> String
|
37
37
|
def run_in_isolation(&_blk)
|
38
38
|
read, write = IO.pipe
|
39
39
|
read.binmode
|
@@ -78,11 +78,11 @@ module Tapioca
|
|
78
78
|
|
79
79
|
requires_ancestor { Kernel }
|
80
80
|
|
81
|
-
ORIG_ARGV =
|
81
|
+
ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV) #: as !nil
|
82
82
|
|
83
83
|
# Crazy H4X to get this working in windows / jruby with
|
84
84
|
# no forking.
|
85
|
-
|
85
|
+
#: ?{ (?) -> untyped } -> String
|
86
86
|
def run_in_isolation(&_blk)
|
87
87
|
this = T.cast(self, Minitest::Test)
|
88
88
|
require "tempfile"
|