tapioca 0.16.9 → 0.17.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +21 -0
- data/exe/tapioca +6 -1
- data/lib/ruby_lsp/tapioca/addon.rb +73 -43
- data/lib/ruby_lsp/tapioca/run_gem_rbi_check.rb +43 -43
- data/lib/ruby_lsp/tapioca/server_addon.rb +13 -10
- data/lib/tapioca/bundler_ext/auto_require_hook.rb +6 -14
- data/lib/tapioca/cli.rb +16 -8
- data/lib/tapioca/commands/abstract_dsl.rb +39 -66
- data/lib/tapioca/commands/abstract_gem.rb +25 -46
- data/lib/tapioca/commands/annotations.rb +28 -34
- data/lib/tapioca/commands/check_shims.rb +6 -15
- data/lib/tapioca/commands/command.rb +12 -26
- data/lib/tapioca/commands/command_without_tracker.rb +2 -5
- 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 +5 -9
- 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 +36 -63
- data/lib/tapioca/dsl/compilers/aasm.rb +33 -44
- data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +8 -7
- data/lib/tapioca/dsl/compilers/action_mailer.rb +6 -5
- data/lib/tapioca/dsl/compilers/action_text.rb +6 -5
- data/lib/tapioca/dsl/compilers/active_job.rb +6 -10
- data/lib/tapioca/dsl/compilers/active_model_attributes.rb +10 -11
- data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +5 -6
- data/lib/tapioca/dsl/compilers/active_model_validations_confirmation.rb +5 -12
- data/lib/tapioca/dsl/compilers/active_record_associations.rb +17 -44
- data/lib/tapioca/dsl/compilers/active_record_columns.rb +20 -26
- data/lib/tapioca/dsl/compilers/active_record_delegated_types.rb +9 -8
- data/lib/tapioca/dsl/compilers/active_record_enum.rb +7 -6
- data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +54 -62
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +148 -209
- data/lib/tapioca/dsl/compilers/active_record_scope.rb +8 -13
- data/lib/tapioca/dsl/compilers/active_record_secure_token.rb +5 -4
- data/lib/tapioca/dsl/compilers/active_record_store.rb +5 -4
- data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +19 -28
- data/lib/tapioca/dsl/compilers/active_resource.rb +19 -21
- data/lib/tapioca/dsl/compilers/active_storage.rb +6 -14
- data/lib/tapioca/dsl/compilers/active_support_concern.rb +9 -8
- data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +8 -7
- data/lib/tapioca/dsl/compilers/active_support_time_ext.rb +5 -4
- data/lib/tapioca/dsl/compilers/config.rb +5 -4
- data/lib/tapioca/dsl/compilers/frozen_record.rb +7 -11
- data/lib/tapioca/dsl/compilers/graphql_input_object.rb +9 -10
- data/lib/tapioca/dsl/compilers/graphql_mutation.rb +6 -10
- data/lib/tapioca/dsl/compilers/identity_cache.rb +11 -39
- data/lib/tapioca/dsl/compilers/json_api_client_resource.rb +9 -18
- data/lib/tapioca/dsl/compilers/kredis.rb +7 -8
- data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +5 -4
- data/lib/tapioca/dsl/compilers/protobuf.rb +13 -26
- data/lib/tapioca/dsl/compilers/rails_generators.rb +9 -11
- data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +23 -13
- data/lib/tapioca/dsl/compilers/smart_properties.rb +32 -38
- data/lib/tapioca/dsl/compilers/state_machines.rb +15 -26
- data/lib/tapioca/dsl/compilers/url_helpers.rb +10 -9
- 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 +30 -58
- data/lib/tapioca/executor.rb +6 -12
- data/lib/tapioca/gem/events.rb +24 -34
- data/lib/tapioca/gem/listeners/base.rb +7 -10
- 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 +36 -47
- 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 +15 -8
- data/lib/tapioca/gem/listeners/subconstants.rb +5 -4
- data/lib/tapioca/gem/listeners/yard_doc.rb +30 -23
- data/lib/tapioca/gem/pipeline.rb +107 -91
- data/lib/tapioca/gem_info.rb +1 -1
- data/lib/tapioca/gemfile.rb +64 -73
- data/lib/tapioca/helpers/cli_helper.rb +4 -7
- data/lib/tapioca/helpers/config_helper.rb +17 -29
- data/lib/tapioca/helpers/env_helper.rb +2 -5
- 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 +76 -73
- 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 +7 -10
- data/lib/tapioca/helpers/test/dsl_compiler.rb +20 -33
- data/lib/tapioca/helpers/test/isolation.rb +10 -14
- data/lib/tapioca/helpers/test/template.rb +6 -11
- data/lib/tapioca/internal.rb +18 -8
- data/lib/tapioca/loaders/dsl.rb +11 -19
- data/lib/tapioca/loaders/gem.rb +6 -21
- data/lib/tapioca/loaders/loader.rb +21 -39
- 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 -9
- data/lib/tapioca/runtime/attached_class_of_32.rb +1 -1
- data/lib/tapioca/runtime/attached_class_of_legacy.rb +2 -5
- 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 +81 -60
- data/lib/tapioca/runtime/source_location.rb +44 -0
- data/lib/tapioca/runtime/trackers/autoload.rb +7 -9
- data/lib/tapioca/runtime/trackers/constant_definition.rb +18 -14
- data/lib/tapioca/runtime/trackers/method_definition.rb +65 -0
- data/lib/tapioca/runtime/trackers/mixin.rb +8 -11
- data/lib/tapioca/runtime/trackers/required_ancestor.rb +3 -3
- data/lib/tapioca/runtime/trackers/tracker.rb +3 -6
- data/lib/tapioca/runtime/trackers.rb +5 -8
- data/lib/tapioca/sorbet_ext/generic_name_patch.rb +9 -15
- data/lib/tapioca/sorbet_ext/name_patch.rb +2 -2
- 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 +27 -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
|
|
@@ -27,13 +28,10 @@ module Tapioca
|
|
|
27
28
|
Marshal.load(serialized)
|
|
28
29
|
end
|
|
29
30
|
|
|
31
|
+
# @requires_ancestor: Kernel
|
|
30
32
|
module Forking
|
|
31
33
|
extend T::Sig
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
requires_ancestor { Kernel }
|
|
35
|
-
|
|
36
|
-
sig { params(_blk: T.untyped).returns(String) }
|
|
34
|
+
#: ?{ (?) -> untyped } -> String
|
|
37
35
|
def run_in_isolation(&_blk)
|
|
38
36
|
read, write = IO.pipe
|
|
39
37
|
read.binmode
|
|
@@ -67,22 +65,20 @@ module Tapioca
|
|
|
67
65
|
result = read.read
|
|
68
66
|
read.close
|
|
69
67
|
|
|
70
|
-
Process.wait2(
|
|
71
|
-
|
|
68
|
+
Process.wait2(pid)
|
|
69
|
+
result.unpack1("m")
|
|
72
70
|
end
|
|
73
71
|
end
|
|
74
72
|
|
|
73
|
+
# @requires_ancestor: Kernel
|
|
75
74
|
module Subprocess
|
|
76
75
|
extend T::Sig
|
|
77
|
-
extend T::Helpers
|
|
78
|
-
|
|
79
|
-
requires_ancestor { Kernel }
|
|
80
76
|
|
|
81
|
-
ORIG_ARGV =
|
|
77
|
+
ORIG_ARGV = ARGV.dup #: Array[String]
|
|
82
78
|
|
|
83
79
|
# Crazy H4X to get this working in windows / jruby with
|
|
84
80
|
# no forking.
|
|
85
|
-
|
|
81
|
+
#: ?{ (?) -> untyped } -> String
|
|
86
82
|
def run_in_isolation(&_blk)
|
|
87
83
|
this = T.cast(self, Minitest::Test)
|
|
88
84
|
require "tempfile"
|
|
@@ -4,27 +4,22 @@
|
|
|
4
4
|
module Tapioca
|
|
5
5
|
module Helpers
|
|
6
6
|
module Test
|
|
7
|
+
# @requires_ancestor: Kernel
|
|
7
8
|
module Template
|
|
8
9
|
extend T::Sig
|
|
9
|
-
|
|
10
|
+
ERB_SUPPORTS_KVARGS = ::ERB.instance_method(:initialize).parameters.assoc(:key) #: [Symbol, Symbol]?
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
ERB_SUPPORTS_KVARGS = T.let(
|
|
14
|
-
::ERB.instance_method(:initialize).parameters.assoc(:key), T.nilable([Symbol, Symbol])
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
sig { params(selector: String).returns(T::Boolean) }
|
|
12
|
+
#: (String selector) -> bool
|
|
18
13
|
def ruby_version(selector)
|
|
19
14
|
::Gem::Requirement.new(selector).satisfied_by?(::Gem::Version.new(RUBY_VERSION))
|
|
20
15
|
end
|
|
21
16
|
|
|
22
|
-
|
|
17
|
+
#: (String selector) -> bool
|
|
23
18
|
def rails_version(selector)
|
|
24
19
|
::Gem::Requirement.new(selector).satisfied_by?(ActiveSupport.gem_version)
|
|
25
20
|
end
|
|
26
21
|
|
|
27
|
-
|
|
22
|
+
#: (String src, ?trim_mode: String) -> String
|
|
28
23
|
def template(src, trim_mode: ">")
|
|
29
24
|
erb = if ERB_SUPPORTS_KVARGS
|
|
30
25
|
::ERB.new(src, trim_mode: trim_mode)
|
|
@@ -35,7 +30,7 @@ module Tapioca
|
|
|
35
30
|
erb.result(binding)
|
|
36
31
|
end
|
|
37
32
|
|
|
38
|
-
|
|
33
|
+
#: (String str, Integer indent) -> String
|
|
39
34
|
def indented(str, indent)
|
|
40
35
|
str.lines.map! do |line|
|
|
41
36
|
next line if line.chomp.empty?
|
data/lib/tapioca/internal.rb
CHANGED
|
@@ -7,6 +7,24 @@ 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
|
+
# Eager load all the autoloads at this point, so that we don't enter into
|
|
20
|
+
# a weird loop when the autoloads get triggered and we try to require the file.
|
|
21
|
+
# This is especially important since Prism has a few autoloaded constants that
|
|
22
|
+
# should NOT be rewritten (since they are needed for the rewriting itself), so
|
|
23
|
+
# should be loaded as early as possible.
|
|
24
|
+
Tapioca::Runtime::Trackers::Autoload.eager_load_all!
|
|
25
|
+
require "tapioca/rbs/rewriter"
|
|
26
|
+
# ^ Do not change the order of these requires
|
|
27
|
+
|
|
10
28
|
require "benchmark"
|
|
11
29
|
require "bundler"
|
|
12
30
|
require "erb"
|
|
@@ -25,14 +43,6 @@ require "yaml"
|
|
|
25
43
|
require "yard-sorbet"
|
|
26
44
|
require "prism"
|
|
27
45
|
|
|
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
46
|
require "tapioca/helpers/gem_helper"
|
|
37
47
|
require "tapioca/helpers/git_attributes"
|
|
38
48
|
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)
|
|
@@ -3,29 +3,20 @@
|
|
|
3
3
|
|
|
4
4
|
module Tapioca
|
|
5
5
|
module Loaders
|
|
6
|
+
# @abstract
|
|
6
7
|
class Loader
|
|
7
8
|
extend T::Sig
|
|
8
|
-
extend T::Helpers
|
|
9
|
-
|
|
10
9
|
include Thor::Base
|
|
11
10
|
include CliHelper
|
|
12
11
|
include Tapioca::GemHelper
|
|
13
12
|
|
|
14
|
-
abstract
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def load; end
|
|
13
|
+
# @abstract
|
|
14
|
+
#: -> void
|
|
15
|
+
def load = raise NotImplementedError, "Abstract method called"
|
|
18
16
|
|
|
19
17
|
private
|
|
20
18
|
|
|
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
|
|
19
|
+
#: (Tapioca::Gemfile gemfile, String? initialize_file, String? require_file, bool halt_upon_load_error) -> void
|
|
29
20
|
def load_bundle(gemfile, initialize_file, require_file, halt_upon_load_error)
|
|
30
21
|
require_helper(initialize_file)
|
|
31
22
|
|
|
@@ -38,14 +29,7 @@ module Tapioca
|
|
|
38
29
|
load_rails_engines
|
|
39
30
|
end
|
|
40
31
|
|
|
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
|
|
32
|
+
#: (?environment_load: bool, ?eager_load: bool, ?app_root: String, ?halt_upon_load_error: bool) -> void
|
|
49
33
|
def load_rails_application(environment_load: false, eager_load: false, app_root: ".", halt_upon_load_error: true)
|
|
50
34
|
return unless File.exist?(File.expand_path("config/application.rb", app_root))
|
|
51
35
|
|
|
@@ -85,7 +69,7 @@ module Tapioca
|
|
|
85
69
|
say("Continuing RBI generation without loading the Rails application.")
|
|
86
70
|
end
|
|
87
71
|
|
|
88
|
-
|
|
72
|
+
#: -> void
|
|
89
73
|
def load_rails_engines
|
|
90
74
|
return if engines.empty?
|
|
91
75
|
|
|
@@ -110,29 +94,25 @@ module Tapioca
|
|
|
110
94
|
end
|
|
111
95
|
end
|
|
112
96
|
|
|
113
|
-
|
|
97
|
+
#: -> void
|
|
114
98
|
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
99
|
# We use a fresh loader to load the engine directories, so that we don't interfere with
|
|
118
100
|
# any of the existing loaders.
|
|
119
101
|
autoloader = Zeitwerk::Loader.new
|
|
120
102
|
|
|
121
103
|
engines.each do |engine|
|
|
122
104
|
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
105
|
autoloader.push_dir(path)
|
|
106
|
+
rescue Zeitwerk::Error
|
|
107
|
+
# The path is not an existing directory, or it is managed by
|
|
108
|
+
# some other loader, ..., it is fine, just skip it.
|
|
129
109
|
end
|
|
130
110
|
end
|
|
131
111
|
|
|
132
112
|
autoloader.setup
|
|
133
113
|
end
|
|
134
114
|
|
|
135
|
-
|
|
115
|
+
#: -> void
|
|
136
116
|
def load_engines_in_classic_mode
|
|
137
117
|
# This is code adapted from `Rails::Engine#eager_load!` in
|
|
138
118
|
# https://github.com/rails/rails/blob/d9e188dbab81b412f73dfb7763318d52f360af49/railties/lib/rails/engine.rb#L489-L495
|
|
@@ -150,14 +130,14 @@ module Tapioca
|
|
|
150
130
|
end
|
|
151
131
|
end
|
|
152
132
|
|
|
153
|
-
|
|
133
|
+
#: -> bool
|
|
154
134
|
def zeitwerk_mode?
|
|
155
135
|
Rails.respond_to?(:autoloaders) &&
|
|
156
136
|
Rails.autoloaders.respond_to?(:zeitwerk_enabled?) &&
|
|
157
137
|
Rails.autoloaders.zeitwerk_enabled?
|
|
158
138
|
end
|
|
159
139
|
|
|
160
|
-
|
|
140
|
+
#: { -> void } -> void
|
|
161
141
|
def with_rails_application(&blk)
|
|
162
142
|
# Store the current Rails.application object so that we can restore it
|
|
163
143
|
rails_application = T.unsafe(Rails.application)
|
|
@@ -174,7 +154,8 @@ module Tapioca
|
|
|
174
154
|
Rails.app_class = Rails.application = rails_application
|
|
175
155
|
end
|
|
176
156
|
|
|
177
|
-
|
|
157
|
+
# @without_runtime
|
|
158
|
+
#: -> Array[singleton(Rails::Engine)]
|
|
178
159
|
def engines
|
|
179
160
|
return [] unless defined?(Rails::Engine)
|
|
180
161
|
|
|
@@ -188,14 +169,14 @@ module Tapioca
|
|
|
188
169
|
.reject { |engine| gem_in_app_dir?(project_path, engine.config.root.to_path) }
|
|
189
170
|
end
|
|
190
171
|
|
|
191
|
-
|
|
172
|
+
#: (String path) -> void
|
|
192
173
|
def safe_require(path)
|
|
193
174
|
require path
|
|
194
175
|
rescue LoadError
|
|
195
176
|
nil
|
|
196
177
|
end
|
|
197
178
|
|
|
198
|
-
|
|
179
|
+
#: -> void
|
|
199
180
|
def eager_load_rails_app
|
|
200
181
|
application = Rails.application
|
|
201
182
|
|
|
@@ -216,7 +197,7 @@ module Tapioca
|
|
|
216
197
|
end
|
|
217
198
|
end
|
|
218
199
|
|
|
219
|
-
|
|
200
|
+
#: (String? file) -> void
|
|
220
201
|
def require_helper(file)
|
|
221
202
|
return unless file
|
|
222
203
|
|
|
@@ -230,7 +211,8 @@ module Tapioca
|
|
|
230
211
|
# The `eager_load_paths` method still exists, but doesn't return all paths anymore and causes Tapioca to miss some
|
|
231
212
|
# engine paths. The following commit is the change:
|
|
232
213
|
# https://github.com/rails/rails/commit/ebfca905db14020589c22e6937382e6f8f687664
|
|
233
|
-
|
|
214
|
+
# @without_runtime
|
|
215
|
+
#: (singleton(Rails::Engine) engine) -> Array[String]
|
|
234
216
|
def eager_load_paths(engine)
|
|
235
217
|
config = engine.config
|
|
236
218
|
|
|
@@ -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 if defined?(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, encoding: "UTF-8")
|
|
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 Spoom::Sorbet::Translate::Error
|
|
53
|
+
# If we can't translate the RBS comments back into Sorbet's signatures, we just skip the file.
|
|
54
|
+
source
|
|
55
|
+
end
|