tapioca 0.16.11 → 0.17.1
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 +8 -7
- data/lib/tapioca/helpers/test/template.rb +5 -7
- data/lib/tapioca/internal.rb +12 -8
- data/lib/tapioca/loaders/dsl.rb +11 -19
- data/lib/tapioca/loaders/gem.rb +6 -21
- data/lib/tapioca/loaders/loader.rb +17 -33
- 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
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module Tapioca
|
@@ -13,12 +13,13 @@ 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
|
20
20
|
end
|
21
21
|
|
22
|
+
#: -> Object
|
22
23
|
def run
|
23
24
|
serialized = T.unsafe(self).run_in_isolation do
|
24
25
|
super
|
@@ -33,7 +34,7 @@ module Tapioca
|
|
33
34
|
|
34
35
|
requires_ancestor { Kernel }
|
35
36
|
|
36
|
-
|
37
|
+
#: ?{ (?) -> untyped } -> String
|
37
38
|
def run_in_isolation(&_blk)
|
38
39
|
read, write = IO.pipe
|
39
40
|
read.binmode
|
@@ -67,8 +68,8 @@ module Tapioca
|
|
67
68
|
result = read.read
|
68
69
|
read.close
|
69
70
|
|
70
|
-
Process.wait2(
|
71
|
-
|
71
|
+
Process.wait2(pid)
|
72
|
+
result.unpack1("m")
|
72
73
|
end
|
73
74
|
end
|
74
75
|
|
@@ -78,11 +79,11 @@ module Tapioca
|
|
78
79
|
|
79
80
|
requires_ancestor { Kernel }
|
80
81
|
|
81
|
-
ORIG_ARGV =
|
82
|
+
ORIG_ARGV = ARGV.dup #: Array[String]
|
82
83
|
|
83
84
|
# Crazy H4X to get this working in windows / jruby with
|
84
85
|
# no forking.
|
85
|
-
|
86
|
+
#: ?{ (?) -> untyped } -> String
|
86
87
|
def run_in_isolation(&_blk)
|
87
88
|
this = T.cast(self, Minitest::Test)
|
88
89
|
require "tempfile"
|
@@ -10,21 +10,19 @@ module Tapioca
|
|
10
10
|
|
11
11
|
requires_ancestor { Kernel }
|
12
12
|
|
13
|
-
ERB_SUPPORTS_KVARGS =
|
14
|
-
::ERB.instance_method(:initialize).parameters.assoc(:key), T.nilable([Symbol, Symbol])
|
15
|
-
)
|
13
|
+
ERB_SUPPORTS_KVARGS = ::ERB.instance_method(:initialize).parameters.assoc(:key) #: [Symbol, Symbol]?
|
16
14
|
|
17
|
-
|
15
|
+
#: (String selector) -> bool
|
18
16
|
def ruby_version(selector)
|
19
17
|
::Gem::Requirement.new(selector).satisfied_by?(::Gem::Version.new(RUBY_VERSION))
|
20
18
|
end
|
21
19
|
|
22
|
-
|
20
|
+
#: (String selector) -> bool
|
23
21
|
def rails_version(selector)
|
24
22
|
::Gem::Requirement.new(selector).satisfied_by?(ActiveSupport.gem_version)
|
25
23
|
end
|
26
24
|
|
27
|
-
|
25
|
+
#: (String src, ?trim_mode: String) -> String
|
28
26
|
def template(src, trim_mode: ">")
|
29
27
|
erb = if ERB_SUPPORTS_KVARGS
|
30
28
|
::ERB.new(src, trim_mode: trim_mode)
|
@@ -35,7 +33,7 @@ module Tapioca
|
|
35
33
|
erb.result(binding)
|
36
34
|
end
|
37
35
|
|
38
|
-
|
36
|
+
#: (String str, Integer indent) -> String
|
39
37
|
def indented(str, indent)
|
40
38
|
str.lines.map! do |line|
|
41
39
|
next line if line.chomp.empty?
|
data/lib/tapioca/internal.rb
CHANGED
@@ -7,6 +7,18 @@ require "tapioca"
|
|
7
7
|
require "tapioca/runtime/reflection"
|
8
8
|
require "tapioca/runtime/trackers"
|
9
9
|
|
10
|
+
require "tapioca/runtime/dynamic_mixin_compiler"
|
11
|
+
require "tapioca/sorbet_ext/backcompat_patches"
|
12
|
+
require "tapioca/sorbet_ext/name_patch"
|
13
|
+
require "tapioca/sorbet_ext/generic_name_patch"
|
14
|
+
require "tapioca/sorbet_ext/proc_bind_patch"
|
15
|
+
require "tapioca/runtime/generic_type_registry"
|
16
|
+
|
17
|
+
# The rewriter needs to be loaded very early so RBS comments within Tapioca itself are rewritten
|
18
|
+
require "spoom"
|
19
|
+
require "tapioca/rbs/rewriter"
|
20
|
+
# ^ Do not change the order of these requires
|
21
|
+
|
10
22
|
require "benchmark"
|
11
23
|
require "bundler"
|
12
24
|
require "erb"
|
@@ -25,14 +37,6 @@ require "yaml"
|
|
25
37
|
require "yard-sorbet"
|
26
38
|
require "prism"
|
27
39
|
|
28
|
-
require "tapioca/runtime/dynamic_mixin_compiler"
|
29
|
-
require "tapioca/sorbet_ext/backcompat_patches"
|
30
|
-
require "tapioca/sorbet_ext/name_patch"
|
31
|
-
require "tapioca/sorbet_ext/generic_name_patch"
|
32
|
-
require "tapioca/sorbet_ext/proc_bind_patch"
|
33
|
-
require "tapioca/runtime/generic_type_registry"
|
34
|
-
|
35
|
-
require "spoom"
|
36
40
|
require "tapioca/helpers/gem_helper"
|
37
41
|
require "tapioca/helpers/git_attributes"
|
38
42
|
require "tapioca/helpers/sorbet_helper"
|
data/lib/tapioca/loaders/dsl.rb
CHANGED
@@ -9,14 +9,7 @@ module Tapioca
|
|
9
9
|
class << self
|
10
10
|
extend T::Sig
|
11
11
|
|
12
|
-
|
13
|
-
params(
|
14
|
-
tapioca_path: String,
|
15
|
-
eager_load: T::Boolean,
|
16
|
-
app_root: String,
|
17
|
-
halt_upon_load_error: T::Boolean,
|
18
|
-
).void
|
19
|
-
end
|
12
|
+
#: (tapioca_path: String, ?eager_load: bool, ?app_root: String, ?halt_upon_load_error: bool) -> void
|
20
13
|
def load_application(
|
21
14
|
tapioca_path:,
|
22
15
|
eager_load: true,
|
@@ -32,20 +25,21 @@ module Tapioca
|
|
32
25
|
end
|
33
26
|
end
|
34
27
|
|
35
|
-
|
28
|
+
# @override
|
29
|
+
#: -> void
|
36
30
|
def load
|
37
31
|
load_dsl_extensions
|
38
32
|
load_application
|
39
33
|
load_dsl_compilers
|
40
34
|
end
|
41
35
|
|
42
|
-
|
36
|
+
#: -> void
|
43
37
|
def load_dsl_extensions_and_compilers
|
44
38
|
load_dsl_extensions
|
45
39
|
load_dsl_compilers
|
46
40
|
end
|
47
41
|
|
48
|
-
|
42
|
+
#: -> void
|
49
43
|
def reload_custom_compilers
|
50
44
|
# Remove all loaded custom compilers
|
51
45
|
::Tapioca::Dsl::Compiler.descendants.each do |compiler|
|
@@ -68,9 +62,7 @@ module Tapioca
|
|
68
62
|
|
69
63
|
protected
|
70
64
|
|
71
|
-
|
72
|
-
params(tapioca_path: String, eager_load: T::Boolean, app_root: String, halt_upon_load_error: T::Boolean).void
|
73
|
-
end
|
65
|
+
#: (tapioca_path: String, ?eager_load: bool, ?app_root: String, ?halt_upon_load_error: bool) -> void
|
74
66
|
def initialize(tapioca_path:, eager_load: true, app_root: ".", halt_upon_load_error: true)
|
75
67
|
super()
|
76
68
|
|
@@ -78,10 +70,10 @@ module Tapioca
|
|
78
70
|
@eager_load = eager_load
|
79
71
|
@app_root = app_root
|
80
72
|
@halt_upon_load_error = halt_upon_load_error
|
81
|
-
@custom_compiler_paths =
|
73
|
+
@custom_compiler_paths = [] #: Array[String]
|
82
74
|
end
|
83
75
|
|
84
|
-
|
76
|
+
#: -> void
|
85
77
|
def load_dsl_extensions
|
86
78
|
say("Loading DSL extension classes... ")
|
87
79
|
|
@@ -96,7 +88,7 @@ module Tapioca
|
|
96
88
|
say("Done", :green)
|
97
89
|
end
|
98
90
|
|
99
|
-
|
91
|
+
#: -> void
|
100
92
|
def load_dsl_compilers
|
101
93
|
say("Loading DSL compiler classes... ")
|
102
94
|
|
@@ -116,7 +108,7 @@ module Tapioca
|
|
116
108
|
say("Done", :green)
|
117
109
|
end
|
118
110
|
|
119
|
-
|
111
|
+
#: -> void
|
120
112
|
def load_application
|
121
113
|
say("Loading Rails application... ")
|
122
114
|
|
@@ -132,7 +124,7 @@ module Tapioca
|
|
132
124
|
|
133
125
|
private
|
134
126
|
|
135
|
-
|
127
|
+
#: -> void
|
136
128
|
def load_custom_dsl_compilers
|
137
129
|
@custom_compiler_paths = Dir.glob([
|
138
130
|
"#{@tapioca_path}/generators/**/*.rb", # TODO: Here for backcompat, remove later
|
data/lib/tapioca/loaders/gem.rb
CHANGED
@@ -9,15 +9,7 @@ module Tapioca
|
|
9
9
|
class << self
|
10
10
|
extend T::Sig
|
11
11
|
|
12
|
-
|
13
|
-
params(
|
14
|
-
bundle: Gemfile,
|
15
|
-
prerequire: T.nilable(String),
|
16
|
-
postrequire: String,
|
17
|
-
default_command: String,
|
18
|
-
halt_upon_load_error: T::Boolean,
|
19
|
-
).void
|
20
|
-
end
|
12
|
+
#: (bundle: Gemfile, prerequire: String?, postrequire: String, default_command: String, halt_upon_load_error: bool) -> void
|
21
13
|
def load_application(bundle:, prerequire:, postrequire:, default_command:, halt_upon_load_error:)
|
22
14
|
loader = new(
|
23
15
|
bundle: bundle,
|
@@ -30,22 +22,15 @@ module Tapioca
|
|
30
22
|
end
|
31
23
|
end
|
32
24
|
|
33
|
-
|
25
|
+
# @override
|
26
|
+
#: -> void
|
34
27
|
def load
|
35
28
|
require_gem_file
|
36
29
|
end
|
37
30
|
|
38
31
|
protected
|
39
32
|
|
40
|
-
|
41
|
-
params(
|
42
|
-
bundle: Gemfile,
|
43
|
-
prerequire: T.nilable(String),
|
44
|
-
postrequire: String,
|
45
|
-
default_command: String,
|
46
|
-
halt_upon_load_error: T::Boolean,
|
47
|
-
).void
|
48
|
-
end
|
33
|
+
#: (bundle: Gemfile, prerequire: String?, postrequire: String, default_command: String, halt_upon_load_error: bool) -> void
|
49
34
|
def initialize(bundle:, prerequire:, postrequire:, default_command:, halt_upon_load_error:)
|
50
35
|
super()
|
51
36
|
|
@@ -56,7 +41,7 @@ module Tapioca
|
|
56
41
|
@halt_upon_load_error = halt_upon_load_error
|
57
42
|
end
|
58
43
|
|
59
|
-
|
44
|
+
#: -> void
|
60
45
|
def require_gem_file
|
61
46
|
say("Requiring all gems to prepare for compiling... ")
|
62
47
|
begin
|
@@ -76,7 +61,7 @@ module Tapioca
|
|
76
61
|
puts
|
77
62
|
end
|
78
63
|
|
79
|
-
|
64
|
+
#: (String file, LoadError error) -> void
|
80
65
|
def explain_failed_require(file, error)
|
81
66
|
say_error("\n\nLoadError: #{error}", :bold, :red)
|
82
67
|
say_error("\nTapioca could not load all the gems required by your application.", :yellow)
|
@@ -18,14 +18,7 @@ module Tapioca
|
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
-
|
22
|
-
params(
|
23
|
-
gemfile: Tapioca::Gemfile,
|
24
|
-
initialize_file: T.nilable(String),
|
25
|
-
require_file: T.nilable(String),
|
26
|
-
halt_upon_load_error: T::Boolean,
|
27
|
-
).void
|
28
|
-
end
|
21
|
+
#: (Tapioca::Gemfile gemfile, String? initialize_file, String? require_file, bool halt_upon_load_error) -> void
|
29
22
|
def load_bundle(gemfile, initialize_file, require_file, halt_upon_load_error)
|
30
23
|
require_helper(initialize_file)
|
31
24
|
|
@@ -38,14 +31,7 @@ module Tapioca
|
|
38
31
|
load_rails_engines
|
39
32
|
end
|
40
33
|
|
41
|
-
|
42
|
-
params(
|
43
|
-
environment_load: T::Boolean,
|
44
|
-
eager_load: T::Boolean,
|
45
|
-
app_root: String,
|
46
|
-
halt_upon_load_error: T::Boolean,
|
47
|
-
).void
|
48
|
-
end
|
34
|
+
#: (?environment_load: bool, ?eager_load: bool, ?app_root: String, ?halt_upon_load_error: bool) -> void
|
49
35
|
def load_rails_application(environment_load: false, eager_load: false, app_root: ".", halt_upon_load_error: true)
|
50
36
|
return unless File.exist?(File.expand_path("config/application.rb", app_root))
|
51
37
|
|
@@ -85,7 +71,7 @@ module Tapioca
|
|
85
71
|
say("Continuing RBI generation without loading the Rails application.")
|
86
72
|
end
|
87
73
|
|
88
|
-
|
74
|
+
#: -> void
|
89
75
|
def load_rails_engines
|
90
76
|
return if engines.empty?
|
91
77
|
|
@@ -110,29 +96,25 @@ module Tapioca
|
|
110
96
|
end
|
111
97
|
end
|
112
98
|
|
113
|
-
|
99
|
+
#: -> void
|
114
100
|
def load_engines_in_zeitwerk_mode
|
115
|
-
# Collect all the directories that are already managed by all existing Zeitwerk loaders.
|
116
|
-
managed_dirs = Zeitwerk::Registry.loaders.flat_map(&:dirs).to_set
|
117
101
|
# We use a fresh loader to load the engine directories, so that we don't interfere with
|
118
102
|
# any of the existing loaders.
|
119
103
|
autoloader = Zeitwerk::Loader.new
|
120
104
|
|
121
105
|
engines.each do |engine|
|
122
106
|
eager_load_paths(engine).each do |path|
|
123
|
-
# Zeitwerk only accepts existing directories in `push_dir`.
|
124
|
-
next unless File.directory?(path)
|
125
|
-
# We should not add directories that are already managed by a Zeitwerk loader.
|
126
|
-
next if managed_dirs.member?(path)
|
127
|
-
|
128
107
|
autoloader.push_dir(path)
|
108
|
+
rescue Zeitwerk::Error
|
109
|
+
# The path is not an existing directory, or it is managed by
|
110
|
+
# some other loader, ..., it is fine, just skip it.
|
129
111
|
end
|
130
112
|
end
|
131
113
|
|
132
114
|
autoloader.setup
|
133
115
|
end
|
134
116
|
|
135
|
-
|
117
|
+
#: -> void
|
136
118
|
def load_engines_in_classic_mode
|
137
119
|
# This is code adapted from `Rails::Engine#eager_load!` in
|
138
120
|
# https://github.com/rails/rails/blob/d9e188dbab81b412f73dfb7763318d52f360af49/railties/lib/rails/engine.rb#L489-L495
|
@@ -150,14 +132,14 @@ module Tapioca
|
|
150
132
|
end
|
151
133
|
end
|
152
134
|
|
153
|
-
|
135
|
+
#: -> bool
|
154
136
|
def zeitwerk_mode?
|
155
137
|
Rails.respond_to?(:autoloaders) &&
|
156
138
|
Rails.autoloaders.respond_to?(:zeitwerk_enabled?) &&
|
157
139
|
Rails.autoloaders.zeitwerk_enabled?
|
158
140
|
end
|
159
141
|
|
160
|
-
|
142
|
+
#: { -> void } -> void
|
161
143
|
def with_rails_application(&blk)
|
162
144
|
# Store the current Rails.application object so that we can restore it
|
163
145
|
rails_application = T.unsafe(Rails.application)
|
@@ -174,7 +156,8 @@ module Tapioca
|
|
174
156
|
Rails.app_class = Rails.application = rails_application
|
175
157
|
end
|
176
158
|
|
177
|
-
|
159
|
+
# @without_runtime
|
160
|
+
#: -> Array[singleton(Rails::Engine)]
|
178
161
|
def engines
|
179
162
|
return [] unless defined?(Rails::Engine)
|
180
163
|
|
@@ -188,14 +171,14 @@ module Tapioca
|
|
188
171
|
.reject { |engine| gem_in_app_dir?(project_path, engine.config.root.to_path) }
|
189
172
|
end
|
190
173
|
|
191
|
-
|
174
|
+
#: (String path) -> void
|
192
175
|
def safe_require(path)
|
193
176
|
require path
|
194
177
|
rescue LoadError
|
195
178
|
nil
|
196
179
|
end
|
197
180
|
|
198
|
-
|
181
|
+
#: -> void
|
199
182
|
def eager_load_rails_app
|
200
183
|
application = Rails.application
|
201
184
|
|
@@ -216,7 +199,7 @@ module Tapioca
|
|
216
199
|
end
|
217
200
|
end
|
218
201
|
|
219
|
-
|
202
|
+
#: (String? file) -> void
|
220
203
|
def require_helper(file)
|
221
204
|
return unless file
|
222
205
|
|
@@ -230,7 +213,8 @@ module Tapioca
|
|
230
213
|
# The `eager_load_paths` method still exists, but doesn't return all paths anymore and causes Tapioca to miss some
|
231
214
|
# engine paths. The following commit is the change:
|
232
215
|
# https://github.com/rails/rails/commit/ebfca905db14020589c22e6937382e6f8f687664
|
233
|
-
|
216
|
+
# @without_runtime
|
217
|
+
#: (singleton(Rails::Engine) engine) -> Array[String]
|
234
218
|
def eager_load_paths(engine)
|
235
219
|
config = engine.config
|
236
220
|
|
@@ -5,7 +5,7 @@ module RBI
|
|
5
5
|
class Tree
|
6
6
|
extend T::Sig
|
7
7
|
|
8
|
-
|
8
|
+
#: (::Module constant) ?{ (Scope scope) -> void } -> Scope
|
9
9
|
def create_path(constant, &block)
|
10
10
|
constant_name = Tapioca::Runtime::Reflection.name_of(constant)
|
11
11
|
raise "given constant does not have a name" unless constant_name
|
@@ -21,72 +21,47 @@ module RBI
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
#: (String name) ?{ (Scope scope) -> void } -> Scope
|
25
25
|
def create_module(name, &block)
|
26
26
|
T.cast(create_node(RBI::Module.new(name)), RBI::Scope).tap do |node|
|
27
27
|
block&.call(node)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
|
-
params(
|
33
|
-
name: String,
|
34
|
-
superclass_name: T.nilable(String),
|
35
|
-
block: T.nilable(T.proc.params(scope: RBI::Scope).void),
|
36
|
-
).returns(Scope)
|
37
|
-
end
|
31
|
+
#: (String name, ?superclass_name: String?) ?{ (RBI::Scope scope) -> void } -> Scope
|
38
32
|
def create_class(name, superclass_name: nil, &block)
|
39
33
|
T.cast(create_node(RBI::Class.new(name, superclass_name: superclass_name)), RBI::Scope).tap do |node|
|
40
34
|
block&.call(node)
|
41
35
|
end
|
42
36
|
end
|
43
37
|
|
44
|
-
|
38
|
+
#: (String name, value: String) -> void
|
45
39
|
def create_constant(name, value:)
|
46
40
|
create_node(RBI::Const.new(name, value))
|
47
41
|
end
|
48
42
|
|
49
|
-
|
43
|
+
#: (String name) -> void
|
50
44
|
def create_include(name)
|
51
45
|
create_node(RBI::Include.new(name))
|
52
46
|
end
|
53
47
|
|
54
|
-
|
48
|
+
#: (String name) -> void
|
55
49
|
def create_extend(name)
|
56
50
|
create_node(RBI::Extend.new(name))
|
57
51
|
end
|
58
52
|
|
59
|
-
|
53
|
+
#: (String name) -> void
|
60
54
|
def create_mixes_in_class_methods(name)
|
61
55
|
create_node(RBI::MixesInClassMethods.new(name))
|
62
56
|
end
|
63
57
|
|
64
|
-
|
65
|
-
params(
|
66
|
-
name: String,
|
67
|
-
type: String,
|
68
|
-
variance: Symbol,
|
69
|
-
fixed: T.nilable(String),
|
70
|
-
upper: T.nilable(String),
|
71
|
-
lower: T.nilable(String),
|
72
|
-
).void
|
73
|
-
end
|
58
|
+
#: (String name, type: String, ?variance: Symbol, ?fixed: String?, ?upper: String?, ?lower: String?) -> void
|
74
59
|
def create_type_variable(name, type:, variance: :invariant, fixed: nil, upper: nil, lower: nil)
|
75
60
|
value = Tapioca::RBIHelper.serialize_type_variable(type, variance, fixed, upper, lower)
|
76
61
|
create_node(RBI::TypeMember.new(name, value))
|
77
62
|
end
|
78
63
|
|
79
|
-
|
80
|
-
params(
|
81
|
-
name: String,
|
82
|
-
parameters: T::Array[TypedParam],
|
83
|
-
return_type: T.nilable(String),
|
84
|
-
class_method: T::Boolean,
|
85
|
-
visibility: RBI::Visibility,
|
86
|
-
comments: T::Array[RBI::Comment],
|
87
|
-
block: T.nilable(T.proc.params(node: RBI::Method).void),
|
88
|
-
).void
|
89
|
-
end
|
64
|
+
#: (String name, ?parameters: Array[TypedParam], ?return_type: String?, ?class_method: bool, ?visibility: RBI::Visibility, ?comments: Array[RBI::Comment]) ?{ (RBI::Method node) -> void } -> void
|
90
65
|
def create_method(name, parameters: [], return_type: nil, class_method: false, visibility: RBI::Public.new,
|
91
66
|
comments: [], &block)
|
92
67
|
return unless Tapioca::RBIHelper.valid_method_name?(name)
|
@@ -114,12 +89,12 @@ module RBI
|
|
114
89
|
|
115
90
|
private
|
116
91
|
|
117
|
-
|
92
|
+
#: -> Hash[String, RBI::Node]
|
118
93
|
def nodes_cache
|
119
|
-
@nodes_cache ||=
|
94
|
+
@nodes_cache ||= {} #: Hash[String, Node]?
|
120
95
|
end
|
121
96
|
|
122
|
-
|
97
|
+
#: (RBI::Node node) -> RBI::Node
|
123
98
|
def create_node(node)
|
124
99
|
cached = nodes_cache[node.to_s]
|
125
100
|
return cached if cached
|
@@ -5,13 +5,7 @@ module Tapioca
|
|
5
5
|
class RBIFormatter < RBI::Formatter
|
6
6
|
extend T::Sig
|
7
7
|
|
8
|
-
|
9
|
-
params(
|
10
|
-
file: RBI::File,
|
11
|
-
command: String,
|
12
|
-
reason: T.nilable(String),
|
13
|
-
).void
|
14
|
-
end
|
8
|
+
#: (RBI::File file, String command, ?reason: String?) -> void
|
15
9
|
def write_header!(file, command, reason: nil)
|
16
10
|
file.comments << RBI::Comment.new("DO NOT EDIT MANUALLY")
|
17
11
|
file.comments << RBI::Comment.new("This is an autogenerated file for #{reason}.") unless reason.nil?
|
@@ -20,7 +14,7 @@ module Tapioca
|
|
20
14
|
file.comments << RBI::BlankLine.new
|
21
15
|
end
|
22
16
|
|
23
|
-
|
17
|
+
#: (RBI::File file) -> void
|
24
18
|
def write_empty_body_comment!(file)
|
25
19
|
file.comments << RBI::BlankLine.new unless file.comments.empty?
|
26
20
|
file.comments << RBI::Comment.new("THIS IS AN EMPTY RBI FILE.")
|
@@ -28,15 +22,12 @@ module Tapioca
|
|
28
22
|
end
|
29
23
|
end
|
30
24
|
|
31
|
-
DEFAULT_RBI_FORMATTER =
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
),
|
40
|
-
RBIFormatter,
|
41
|
-
)
|
25
|
+
DEFAULT_RBI_FORMATTER = RBIFormatter.new(
|
26
|
+
add_sig_templates: false,
|
27
|
+
group_nodes: true,
|
28
|
+
max_line_length: nil,
|
29
|
+
nest_singleton_methods: true,
|
30
|
+
nest_non_public_members: true,
|
31
|
+
sort_nodes: true,
|
32
|
+
) #: RBIFormatter
|
42
33
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "require-hooks/setup"
|
5
|
+
|
6
|
+
# This code rewrites RBS comments back into Sorbet's signatures as the files are being loaded.
|
7
|
+
# This will allow `sorbet-runtime` to wrap the methods as if they were originally written with the `sig{}` blocks.
|
8
|
+
# This will in turn allow Tapioca to use this signatures to generate typed RBI files.
|
9
|
+
|
10
|
+
begin
|
11
|
+
# When in a `bootsnap` environment, files are loaded from the cache and won't trigger the `source_transform` method.
|
12
|
+
# The `require-hooks` gem comes with a `bootsnap` mode that will disable the `bootsnap/compile_cache/iseq` caching.
|
13
|
+
# Sadly, we're way to early in the boot process to use it as bootsnap won't be loaded yet and the `require-hooks`
|
14
|
+
# setup won't pick it up.
|
15
|
+
#
|
16
|
+
# As a workaround, if we can preemptively require `bootsnap` and `bootsnap/compile_cache/iseq` we manually override
|
17
|
+
# the `load_iseq` method to disable the caching mechanism.
|
18
|
+
#
|
19
|
+
# This will make the Rails app load slower but allows us to trigger the RBS -> RBI source transform.
|
20
|
+
require "bootsnap"
|
21
|
+
require "bootsnap/compile_cache/iseq"
|
22
|
+
|
23
|
+
module Bootsnap
|
24
|
+
module CompileCache
|
25
|
+
module ISeq
|
26
|
+
module InstructionSequenceMixin
|
27
|
+
#: (String) -> RubyVM::InstructionSequence
|
28
|
+
def load_iseq(path)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
rescue LoadError
|
36
|
+
# Bootsnap is not in the bundle, we don't need to do anything.
|
37
|
+
end
|
38
|
+
|
39
|
+
# We need to include `T::Sig` very early to make sure that the `sig` method is available since gems using RBS comments
|
40
|
+
# are unlikely to include `T::Sig` in their own classes.
|
41
|
+
Module.include(T::Sig)
|
42
|
+
|
43
|
+
# Trigger the source transformation for each Ruby file being loaded.
|
44
|
+
RequireHooks.source_transform(patterns: ["**/*.rb"]) do |path, source|
|
45
|
+
# The source is most likely nil since no `source_transform` hook was triggered before this one.
|
46
|
+
source ||= File.read(path)
|
47
|
+
|
48
|
+
# For performance reasons, we only rewrite files that use Sorbet.
|
49
|
+
if source =~ /^\s*#\s*typed: (ignore|false|true|strict|strong|__STDLIB_INTERNAL)/
|
50
|
+
Spoom::Sorbet::Translate.rbs_comments_to_sorbet_sigs(source, file: path)
|
51
|
+
end
|
52
|
+
rescue RBI::RBS::MethodTypeTranslator::Error
|
53
|
+
# If we can't translate the RBS comments back into Sorbet's signatures, we just skip the file.
|
54
|
+
source
|
55
|
+
end
|
data/lib/tapioca/repo_index.rb
CHANGED
@@ -9,12 +9,12 @@ module Tapioca
|
|
9
9
|
class << self
|
10
10
|
extend T::Sig
|
11
11
|
|
12
|
-
|
12
|
+
#: (String json) -> RepoIndex
|
13
13
|
def from_json(json)
|
14
14
|
RepoIndex.from_hash(JSON.parse(json))
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
#: (Hash[String, Hash[untyped, untyped]] hash) -> RepoIndex
|
18
18
|
def from_hash(hash)
|
19
19
|
hash.each_with_object(RepoIndex.new) do |(name, _), index|
|
20
20
|
index << name
|
@@ -22,22 +22,22 @@ module Tapioca
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
#: -> void
|
26
26
|
def initialize
|
27
|
-
@entries =
|
27
|
+
@entries = Set.new #: Set[String]
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
#: (String gem_name) -> void
|
31
31
|
def <<(gem_name)
|
32
32
|
@entries.add(gem_name)
|
33
33
|
end
|
34
34
|
|
35
|
-
|
35
|
+
#: -> T::Enumerable[String]
|
36
36
|
def gems
|
37
37
|
@entries.sort
|
38
38
|
end
|
39
39
|
|
40
|
-
|
40
|
+
#: (String gem_name) -> bool
|
41
41
|
def has_gem?(gem_name)
|
42
42
|
@entries.include?(gem_name)
|
43
43
|
end
|
@@ -10,7 +10,7 @@ module Tapioca
|
|
10
10
|
module AttachedClassOf
|
11
11
|
extend T::Sig
|
12
12
|
|
13
|
-
|
13
|
+
#: (Class singleton_class) -> Module?
|
14
14
|
def attached_class_of(singleton_class)
|
15
15
|
result = singleton_class.attached_object
|
16
16
|
Module === result ? result : nil
|