tapioca 0.9.4 → 0.10.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/LICENSE.txt +21 -0
- data/README.md +48 -22
- data/lib/tapioca/cli.rb +17 -23
- data/lib/tapioca/commands/annotations.rb +2 -2
- data/lib/tapioca/commands/dsl.rb +43 -65
- data/lib/tapioca/commands/gem.rb +18 -50
- data/lib/tapioca/commands/todo.rb +1 -2
- data/lib/tapioca/dsl/compiler.rb +34 -37
- data/lib/tapioca/dsl/compilers/aasm.rb +7 -3
- data/lib/tapioca/dsl/compilers/action_controller_helpers.rb +7 -3
- data/lib/tapioca/dsl/compilers/action_mailer.rb +7 -3
- data/lib/tapioca/dsl/compilers/active_job.rb +7 -3
- data/lib/tapioca/dsl/compilers/active_model_attributes.rb +9 -5
- data/lib/tapioca/dsl/compilers/active_model_secure_password.rb +11 -7
- data/lib/tapioca/dsl/compilers/active_record_associations.rb +7 -3
- data/lib/tapioca/dsl/compilers/active_record_columns.rb +7 -3
- data/lib/tapioca/dsl/compilers/active_record_enum.rb +7 -3
- data/lib/tapioca/dsl/compilers/active_record_fixtures.rb +8 -4
- data/lib/tapioca/dsl/compilers/active_record_relations.rb +7 -3
- data/lib/tapioca/dsl/compilers/active_record_scope.rb +5 -3
- data/lib/tapioca/dsl/compilers/active_record_typed_store.rb +8 -4
- data/lib/tapioca/dsl/compilers/active_resource.rb +7 -3
- data/lib/tapioca/dsl/compilers/active_storage.rb +9 -5
- data/lib/tapioca/dsl/compilers/active_support_concern.rb +21 -18
- data/lib/tapioca/dsl/compilers/active_support_current_attributes.rb +7 -3
- data/lib/tapioca/dsl/compilers/config.rb +12 -8
- data/lib/tapioca/dsl/compilers/frozen_record.rb +7 -3
- data/lib/tapioca/dsl/compilers/graphql_input_object.rb +71 -0
- data/lib/tapioca/dsl/compilers/graphql_mutation.rb +81 -0
- data/lib/tapioca/dsl/compilers/identity_cache.rb +8 -4
- data/lib/tapioca/dsl/compilers/mixed_in_class_attributes.rb +9 -5
- data/lib/tapioca/dsl/compilers/protobuf.rb +69 -25
- data/lib/tapioca/dsl/compilers/rails_generators.rb +12 -8
- data/lib/tapioca/dsl/compilers/sidekiq_worker.rb +7 -3
- data/lib/tapioca/dsl/compilers/smart_properties.rb +10 -6
- data/lib/tapioca/dsl/compilers/state_machines.rb +7 -3
- data/lib/tapioca/dsl/compilers/url_helpers.rb +29 -26
- data/lib/tapioca/dsl/compilers.rb +0 -5
- data/lib/tapioca/dsl/helpers/active_record_column_type_helper.rb +1 -9
- data/lib/tapioca/dsl/helpers/graphql_type_helper.rb +62 -0
- data/lib/tapioca/dsl/pipeline.rb +19 -11
- data/lib/tapioca/gem/listeners/source_location.rb +16 -9
- data/lib/tapioca/gemfile.rb +30 -0
- data/lib/tapioca/helpers/config_helper.rb +2 -2
- data/lib/tapioca/helpers/rbi_helper.rb +43 -30
- data/lib/tapioca/helpers/source_uri.rb +77 -0
- data/lib/tapioca/helpers/test/dsl_compiler.rb +1 -1
- data/lib/tapioca/helpers/test/isolation.rb +7 -3
- data/lib/tapioca/internal.rb +5 -1
- data/lib/tapioca/loaders/dsl.rb +84 -0
- data/lib/tapioca/loaders/gem.rb +85 -0
- data/lib/tapioca/{runtime → loaders}/loader.rb +39 -31
- data/lib/tapioca/repo_index.rb +12 -8
- data/lib/tapioca/runtime/dynamic_mixin_compiler.rb +2 -2
- data/lib/tapioca/runtime/trackers/constant_definition.rb +15 -13
- data/lib/tapioca/runtime/trackers/mixin.rb +35 -31
- data/lib/tapioca/runtime/trackers/required_ancestor.rb +21 -19
- data/lib/tapioca/static/requires_compiler.rb +2 -3
- data/lib/tapioca/static/symbol_table_parser.rb +19 -17
- data/lib/tapioca/version.rb +1 -1
- data/lib/tapioca.rb +24 -20
- metadata +10 -5
- data/Gemfile +0 -53
- data/Rakefile +0 -18
data/lib/tapioca/gemfile.rb
CHANGED
@@ -136,6 +136,22 @@ module Tapioca
|
|
136
136
|
extend(T::Sig)
|
137
137
|
include GemHelper
|
138
138
|
|
139
|
+
class << self
|
140
|
+
extend T::Sig
|
141
|
+
|
142
|
+
sig { returns(T::Hash[String, Gemfile::GemSpec]) }
|
143
|
+
def spec_lookup_by_file_path
|
144
|
+
@lookup ||= T.let(
|
145
|
+
[*::Gem::Specification.default_stubs, *::Gem::Specification.stubs]
|
146
|
+
.map! { |spec| new(spec.to_spec) }
|
147
|
+
.flat_map do |spec|
|
148
|
+
spec.files.filter_map { |file| [file.realpath.to_s, spec] if file.exist? }
|
149
|
+
end.to_h,
|
150
|
+
T.nilable(T::Hash[String, Gemfile::GemSpec])
|
151
|
+
)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
139
155
|
IGNORED_GEMS = T.let(
|
140
156
|
[
|
141
157
|
"sorbet", "sorbet-static", "sorbet-runtime", "sorbet-static-and-runtime",
|
@@ -160,6 +176,11 @@ module Tapioca
|
|
160
176
|
@files = T.let(collect_files, T::Array[Pathname])
|
161
177
|
end
|
162
178
|
|
179
|
+
sig { params(other: BasicObject).returns(T::Boolean) }
|
180
|
+
def ==(other)
|
181
|
+
GemSpec === other && other.name == name && other.version == version
|
182
|
+
end
|
183
|
+
|
163
184
|
sig { params(gemfile_dir: String).returns(T::Boolean) }
|
164
185
|
def ignore?(gemfile_dir)
|
165
186
|
gem_ignored? || gem_in_app_dir?(gemfile_dir, full_gem_path)
|
@@ -211,6 +232,15 @@ module Tapioca
|
|
211
232
|
rewriter.tree
|
212
233
|
end
|
213
234
|
|
235
|
+
sig { params(file: Pathname).returns(Pathname) }
|
236
|
+
def relative_path_for(file)
|
237
|
+
if default_gem?
|
238
|
+
file.realpath.relative_path_from(RbConfig::CONFIG["rubylibdir"])
|
239
|
+
else
|
240
|
+
file.realpath.relative_path_from(full_gem_path)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
214
244
|
private
|
215
245
|
|
216
246
|
sig { returns(T::Array[Pathname]) }
|
@@ -100,7 +100,7 @@ module Tapioca
|
|
100
100
|
).returns(T::Array[ConfigError])
|
101
101
|
end
|
102
102
|
def validate_config_options(command_options, config_key, config_options)
|
103
|
-
config_options.
|
103
|
+
config_options.filter_map do |config_option_key, config_option_value|
|
104
104
|
command_option = command_options[config_option_key.to_sym]
|
105
105
|
error_msg = "unknown option `#{config_option_key}` for key `#{config_key}`"
|
106
106
|
next build_error(error_msg) unless command_option
|
@@ -135,7 +135,7 @@ module Tapioca
|
|
135
135
|
all_strings = (config_option_value.keys + config_option_value.values).all? { |v| v.is_a?(String) }
|
136
136
|
next build_error(error_msg) unless all_strings
|
137
137
|
end
|
138
|
-
end
|
138
|
+
end
|
139
139
|
end
|
140
140
|
|
141
141
|
class ConfigErrorMessagePart < T::Struct
|
@@ -8,6 +8,44 @@ module Tapioca
|
|
8
8
|
extend SorbetHelper
|
9
9
|
extend self
|
10
10
|
|
11
|
+
class << self
|
12
|
+
extend T::Sig
|
13
|
+
|
14
|
+
sig do
|
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
|
23
|
+
def serialize_type_variable(type, variance, fixed, upper, lower)
|
24
|
+
variance = nil if variance == :invariant
|
25
|
+
|
26
|
+
bounds = []
|
27
|
+
bounds << "fixed: #{fixed}" if fixed
|
28
|
+
bounds << "lower: #{lower}" if lower
|
29
|
+
bounds << "upper: #{upper}" if upper
|
30
|
+
|
31
|
+
parameters = []
|
32
|
+
block = []
|
33
|
+
|
34
|
+
parameters << ":#{variance}" if variance
|
35
|
+
|
36
|
+
if sorbet_supports?(:type_variable_block_syntax)
|
37
|
+
block = bounds
|
38
|
+
else
|
39
|
+
parameters.concat(bounds)
|
40
|
+
end
|
41
|
+
|
42
|
+
serialized = type.dup
|
43
|
+
serialized << "(#{parameters.join(", ")})" unless parameters.empty?
|
44
|
+
serialized << " { { #{block.join(", ")} } }" unless block.empty?
|
45
|
+
serialized
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
11
49
|
sig { params(name: String, type: String).returns(RBI::TypedParam) }
|
12
50
|
def create_param(name, type:)
|
13
51
|
create_typed_param(RBI::Param.new(name), type)
|
@@ -57,38 +95,13 @@ module Tapioca
|
|
57
95
|
.gsub(".params()", "")
|
58
96
|
end
|
59
97
|
|
60
|
-
sig
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
fixed: T.nilable(String),
|
65
|
-
upper: T.nilable(String),
|
66
|
-
lower: T.nilable(String)
|
67
|
-
).returns(String)
|
68
|
-
end
|
69
|
-
def self.serialize_type_variable(type, variance, fixed, upper, lower)
|
70
|
-
variance = nil if variance == :invariant
|
71
|
-
|
72
|
-
bounds = []
|
73
|
-
bounds << "fixed: #{fixed}" if fixed
|
74
|
-
bounds << "lower: #{lower}" if lower
|
75
|
-
bounds << "upper: #{upper}" if upper
|
76
|
-
|
77
|
-
parameters = []
|
78
|
-
block = []
|
79
|
-
|
80
|
-
parameters << ":#{variance}" if variance
|
81
|
-
|
82
|
-
if sorbet_supports?(:type_variable_block_syntax)
|
83
|
-
block = bounds
|
98
|
+
sig { params(type: String).returns(String) }
|
99
|
+
def as_nilable_type(type)
|
100
|
+
if type.start_with?("T.nilable(", "::T.nilable(") || type == "T.untyped" || type == "::T.untyped"
|
101
|
+
type
|
84
102
|
else
|
85
|
-
|
103
|
+
"T.nilable(#{type})"
|
86
104
|
end
|
87
|
-
|
88
|
-
serialized = type.dup
|
89
|
-
serialized << "(#{parameters.join(", ")})" unless parameters.empty?
|
90
|
-
serialized << " { { #{block.join(", ")} } }" unless block.empty?
|
91
|
-
serialized
|
92
105
|
end
|
93
106
|
|
94
107
|
sig { params(name: String).returns(T::Boolean) }
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "uri/file"
|
5
|
+
|
6
|
+
module URI
|
7
|
+
class Source < URI::File
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
COMPONENT = T.let([
|
11
|
+
:scheme,
|
12
|
+
:gem_name,
|
13
|
+
:gem_version,
|
14
|
+
:path,
|
15
|
+
:line_number,
|
16
|
+
].freeze, T::Array[Symbol])
|
17
|
+
|
18
|
+
alias_method(:gem_name, :host)
|
19
|
+
alias_method(:line_number, :fragment)
|
20
|
+
|
21
|
+
sig { returns(T.nilable(String)) }
|
22
|
+
attr_reader :gem_version
|
23
|
+
|
24
|
+
class << self
|
25
|
+
extend T::Sig
|
26
|
+
|
27
|
+
sig do
|
28
|
+
params(
|
29
|
+
gem_name: String,
|
30
|
+
gem_version: T.nilable(String),
|
31
|
+
path: String,
|
32
|
+
line_number: T.nilable(String)
|
33
|
+
).returns(URI::Source)
|
34
|
+
end
|
35
|
+
def build(gem_name:, gem_version:, path:, line_number:)
|
36
|
+
super(
|
37
|
+
{
|
38
|
+
scheme: "source",
|
39
|
+
host: gem_name,
|
40
|
+
path: DEFAULT_PARSER.escape("/#{gem_version}/#{path}"),
|
41
|
+
fragment: line_number,
|
42
|
+
}
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
sig { params(v: T.nilable(String)).void }
|
48
|
+
def set_path(v) # rubocop:disable Naming/AccessorMethodName
|
49
|
+
return if v.nil?
|
50
|
+
|
51
|
+
@gem_version, @path = v.split("/", 2)
|
52
|
+
end
|
53
|
+
|
54
|
+
sig { params(v: T.nilable(String)).returns(T::Boolean) }
|
55
|
+
def check_host(v)
|
56
|
+
return true unless v
|
57
|
+
|
58
|
+
if /[A-Za-z][A-Za-z0-9\-_]*/ !~ v
|
59
|
+
raise InvalidComponentError,
|
60
|
+
"bad component(expected gem name): #{v}"
|
61
|
+
end
|
62
|
+
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
sig { returns(String) }
|
67
|
+
def to_s
|
68
|
+
"source://#{gem_name}/#{gem_version}#{path}##{line_number}"
|
69
|
+
end
|
70
|
+
|
71
|
+
if URI.respond_to?(:register_scheme)
|
72
|
+
URI.register_scheme("SOURCE", self)
|
73
|
+
else
|
74
|
+
@@schemes["SOURCE"] = self
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -79,7 +79,7 @@ module Tapioca
|
|
79
79
|
|
80
80
|
sig { returns(T::Array[String]) }
|
81
81
|
def gathered_constants
|
82
|
-
compiler_class.processable_constants.
|
82
|
+
compiler_class.processable_constants.filter_map(&:name).sort
|
83
83
|
end
|
84
84
|
|
85
85
|
sig { params(constant_name: T.any(Symbol, String)).returns(String) }
|
@@ -10,9 +10,13 @@ module Tapioca
|
|
10
10
|
extend T::Sig
|
11
11
|
require "thread"
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
class << self
|
14
|
+
extend T::Sig
|
15
|
+
|
16
|
+
sig { returns(T::Boolean) }
|
17
|
+
def forking_env?
|
18
|
+
!ENV["NO_FORK"] && Process.respond_to?(:fork)
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
22
|
def run
|
data/lib/tapioca/internal.rb
CHANGED
@@ -27,7 +27,6 @@ require "yard-sorbet"
|
|
27
27
|
|
28
28
|
require "tapioca/runtime/dynamic_mixin_compiler"
|
29
29
|
require "tapioca/helpers/gem_helper"
|
30
|
-
require "tapioca/runtime/loader"
|
31
30
|
|
32
31
|
require "tapioca/helpers/sorbet_helper"
|
33
32
|
require "tapioca/helpers/rbi_helper"
|
@@ -37,6 +36,7 @@ require "tapioca/sorbet_ext/generic_name_patch"
|
|
37
36
|
require "tapioca/sorbet_ext/proc_bind_patch"
|
38
37
|
require "tapioca/runtime/generic_type_registry"
|
39
38
|
|
39
|
+
require "tapioca/helpers/source_uri"
|
40
40
|
require "tapioca/helpers/cli_helper"
|
41
41
|
require "tapioca/helpers/config_helper"
|
42
42
|
require "tapioca/helpers/rbi_files_helper"
|
@@ -50,6 +50,10 @@ require "tapioca/static/symbol_table_parser"
|
|
50
50
|
require "tapioca/static/symbol_loader"
|
51
51
|
require "tapioca/static/requires_compiler"
|
52
52
|
|
53
|
+
require "tapioca/loaders/loader"
|
54
|
+
require "tapioca/loaders/gem"
|
55
|
+
require "tapioca/loaders/dsl"
|
56
|
+
|
53
57
|
require "tapioca/gem"
|
54
58
|
require "tapioca/dsl"
|
55
59
|
require "tapioca/commands"
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Tapioca
|
5
|
+
module Loaders
|
6
|
+
class Dsl < Loader
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
class << self
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
sig { params(tapioca_path: String, eager_load: T::Boolean).void }
|
13
|
+
def load_application(tapioca_path:, eager_load: true)
|
14
|
+
loader = new(tapioca_path: tapioca_path)
|
15
|
+
loader.load
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
sig { override.void }
|
20
|
+
def load
|
21
|
+
load_dsl_extensions
|
22
|
+
load_application
|
23
|
+
abort_if_pending_migrations!
|
24
|
+
load_dsl_compilers
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
sig { params(tapioca_path: String, eager_load: T::Boolean).void }
|
30
|
+
def initialize(tapioca_path:, eager_load: true)
|
31
|
+
super()
|
32
|
+
|
33
|
+
@tapioca_path = tapioca_path
|
34
|
+
@eager_load = eager_load
|
35
|
+
end
|
36
|
+
|
37
|
+
sig { void }
|
38
|
+
def load_dsl_extensions
|
39
|
+
Dir["#{__dir__}/../dsl/extensions/*.rb"].sort.each { |f| require(f) }
|
40
|
+
end
|
41
|
+
|
42
|
+
sig { void }
|
43
|
+
def load_dsl_compilers
|
44
|
+
say("Loading DSL compiler classes... ")
|
45
|
+
|
46
|
+
Dir.glob([
|
47
|
+
"#{@tapioca_path}/generators/**/*.rb", # TODO: Here for backcompat, remove later
|
48
|
+
"#{@tapioca_path}/compilers/**/*.rb",
|
49
|
+
]).each do |compiler|
|
50
|
+
require File.expand_path(compiler)
|
51
|
+
end
|
52
|
+
|
53
|
+
::Gem.find_files("tapioca/dsl/compilers/*.rb").each do |compiler|
|
54
|
+
require File.expand_path(compiler)
|
55
|
+
end
|
56
|
+
|
57
|
+
say("Done", :green)
|
58
|
+
end
|
59
|
+
|
60
|
+
sig { void }
|
61
|
+
def load_application
|
62
|
+
say("Loading Rails application... ")
|
63
|
+
|
64
|
+
load_rails_application(
|
65
|
+
environment_load: true,
|
66
|
+
eager_load: @eager_load
|
67
|
+
)
|
68
|
+
|
69
|
+
say("Done", :green)
|
70
|
+
end
|
71
|
+
|
72
|
+
sig { void }
|
73
|
+
def abort_if_pending_migrations!
|
74
|
+
return unless File.exist?("config/application.rb")
|
75
|
+
return unless defined?(::Rake)
|
76
|
+
|
77
|
+
Rails.application.load_tasks
|
78
|
+
if Rake::Task.task_defined?("db:abort_if_pending_migrations")
|
79
|
+
Rake::Task["db:abort_if_pending_migrations"].invoke
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Tapioca
|
5
|
+
module Loaders
|
6
|
+
class Gem < Loader
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
class << self
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
sig do
|
13
|
+
params(
|
14
|
+
bundle: Gemfile,
|
15
|
+
prerequire: T.nilable(String),
|
16
|
+
postrequire: String,
|
17
|
+
default_command: String
|
18
|
+
).void
|
19
|
+
end
|
20
|
+
def load_application(bundle:, prerequire:, postrequire:, default_command:)
|
21
|
+
loader = new(bundle: bundle,
|
22
|
+
prerequire: prerequire,
|
23
|
+
postrequire: postrequire,
|
24
|
+
default_command: default_command)
|
25
|
+
loader.load
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
sig { override.void }
|
30
|
+
def load
|
31
|
+
require_gem_file
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
sig do
|
37
|
+
params(
|
38
|
+
bundle: Gemfile,
|
39
|
+
prerequire: T.nilable(String),
|
40
|
+
postrequire: String,
|
41
|
+
default_command: String
|
42
|
+
).void
|
43
|
+
end
|
44
|
+
def initialize(bundle:, prerequire:, postrequire:, default_command:)
|
45
|
+
super()
|
46
|
+
|
47
|
+
@bundle = bundle
|
48
|
+
@prerequire = prerequire
|
49
|
+
@postrequire = postrequire
|
50
|
+
@default_command = default_command
|
51
|
+
end
|
52
|
+
|
53
|
+
sig { void }
|
54
|
+
def require_gem_file
|
55
|
+
say("Requiring all gems to prepare for compiling... ")
|
56
|
+
begin
|
57
|
+
load_bundle(@bundle, @prerequire, @postrequire)
|
58
|
+
rescue LoadError => e
|
59
|
+
explain_failed_require(@postrequire, e)
|
60
|
+
exit(1)
|
61
|
+
end
|
62
|
+
|
63
|
+
Runtime::Trackers::Autoload.eager_load_all!
|
64
|
+
|
65
|
+
say(" Done", :green)
|
66
|
+
unless @bundle.missing_specs.empty?
|
67
|
+
say(" completed with missing specs: ")
|
68
|
+
say(@bundle.missing_specs.join(", "), :yellow)
|
69
|
+
end
|
70
|
+
puts
|
71
|
+
end
|
72
|
+
|
73
|
+
sig { params(file: String, error: LoadError).void }
|
74
|
+
def explain_failed_require(file, error)
|
75
|
+
say_error("\n\nLoadError: #{error}", :bold, :red)
|
76
|
+
say_error("\nTapioca could not load all the gems required by your application.", :yellow)
|
77
|
+
say_error("If you populated ", :yellow)
|
78
|
+
say_error("#{file} ", :bold, :blue)
|
79
|
+
say_error("with ", :yellow)
|
80
|
+
say_error("`#{@default_command}`", :bold, :blue)
|
81
|
+
say_error("you should probably review it and remove the faulty line.", :yellow)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -1,12 +1,22 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
module Tapioca
|
5
|
-
module
|
5
|
+
module Loaders
|
6
6
|
class Loader
|
7
|
-
extend
|
8
|
-
|
7
|
+
extend T::Sig
|
8
|
+
extend T::Helpers
|
9
|
+
|
9
10
|
include Thor::Base
|
11
|
+
include CliHelper
|
12
|
+
include Tapioca::GemHelper
|
13
|
+
|
14
|
+
abstract!
|
15
|
+
|
16
|
+
sig { abstract.void }
|
17
|
+
def load; end
|
18
|
+
|
19
|
+
private
|
10
20
|
|
11
21
|
sig do
|
12
22
|
params(gemfile: Tapioca::Gemfile, initialize_file: T.nilable(String), require_file: T.nilable(String)).void
|
@@ -43,16 +53,27 @@ module Tapioca
|
|
43
53
|
say("Continuing RBI generation without loading the Rails application.")
|
44
54
|
end
|
45
55
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
return unless file
|
56
|
+
sig { void }
|
57
|
+
def load_rails_engines
|
58
|
+
rails_engines.each do |engine|
|
59
|
+
errored_files = []
|
51
60
|
|
52
|
-
|
53
|
-
|
61
|
+
engine.config.eager_load_paths.each do |load_path|
|
62
|
+
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
|
63
|
+
require(file)
|
64
|
+
rescue LoadError, StandardError
|
65
|
+
errored_files << file
|
66
|
+
end
|
67
|
+
end
|
54
68
|
|
55
|
-
|
69
|
+
# Try files that have errored one more time
|
70
|
+
# It might have been a load order problem
|
71
|
+
errored_files.each do |file|
|
72
|
+
require(file)
|
73
|
+
rescue LoadError, StandardError
|
74
|
+
nil
|
75
|
+
end
|
76
|
+
end
|
56
77
|
end
|
57
78
|
|
58
79
|
sig { returns(T::Array[T.untyped]) }
|
@@ -110,27 +131,14 @@ module Tapioca
|
|
110
131
|
end
|
111
132
|
end
|
112
133
|
|
113
|
-
sig { void }
|
114
|
-
def
|
115
|
-
|
116
|
-
errored_files = []
|
134
|
+
sig { params(file: T.nilable(String)).void }
|
135
|
+
def require_helper(file)
|
136
|
+
return unless file
|
117
137
|
|
118
|
-
|
119
|
-
|
120
|
-
require(file)
|
121
|
-
rescue LoadError, StandardError
|
122
|
-
errored_files << file
|
123
|
-
end
|
124
|
-
end
|
138
|
+
file = File.absolute_path(file)
|
139
|
+
return unless File.exist?(file)
|
125
140
|
|
126
|
-
|
127
|
-
# It might have been a load order problem
|
128
|
-
errored_files.each do |file|
|
129
|
-
require(file)
|
130
|
-
rescue LoadError, StandardError
|
131
|
-
nil
|
132
|
-
end
|
133
|
-
end
|
141
|
+
require(file)
|
134
142
|
end
|
135
143
|
end
|
136
144
|
end
|
data/lib/tapioca/repo_index.rb
CHANGED
@@ -6,15 +6,19 @@ module Tapioca
|
|
6
6
|
extend T::Sig
|
7
7
|
extend T::Generic
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
class << self
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
sig { params(json: String).returns(RepoIndex) }
|
13
|
+
def from_json(json)
|
14
|
+
RepoIndex.from_hash(JSON.parse(json))
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
sig { params(hash: T::Hash[String, T::Hash[T.untyped, T.untyped]]).returns(RepoIndex) }
|
18
|
+
def from_hash(hash)
|
19
|
+
hash.each_with_object(RepoIndex.new) do |(name, _), index|
|
20
|
+
index << name
|
21
|
+
end
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
@@ -178,7 +178,7 @@ module Tapioca
|
|
178
178
|
|
179
179
|
sig { params(tree: RBI::Tree).returns([T::Array[Module], T::Array[Module]]) }
|
180
180
|
def compile_mixes_in_class_methods(tree)
|
181
|
-
includes = dynamic_includes.
|
181
|
+
includes = dynamic_includes.filter_map do |mod|
|
182
182
|
qname = qualified_name_of(mod)
|
183
183
|
|
184
184
|
next if qname.nil? || qname.empty?
|
@@ -187,7 +187,7 @@ module Tapioca
|
|
187
187
|
tree << RBI::Include.new(qname)
|
188
188
|
|
189
189
|
mod
|
190
|
-
end
|
190
|
+
end
|
191
191
|
|
192
192
|
# If we can generate multiple mixes_in_class_methods, then we want to use all dynamic extends that are not the
|
193
193
|
# constant itself
|
@@ -49,22 +49,24 @@ module Tapioca
|
|
49
49
|
(@class_files[key] ||= Set.new) << loc
|
50
50
|
end
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
class << self
|
53
|
+
def build_constant_location(tp, locations)
|
54
|
+
file = resolve_loc(caller_locations)
|
55
|
+
lineno = file == File.realpath(tp.path) ? tp.lineno : 0
|
55
56
|
|
56
|
-
|
57
|
-
|
57
|
+
ConstantLocation.new(path: file, lineno: lineno)
|
58
|
+
end
|
58
59
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
60
|
+
# Returns the files in which this class or module was opened. Doesn't know
|
61
|
+
# about situations where the class was opened prior to +require+ing,
|
62
|
+
# or where metaprogramming was used via +eval+, etc.
|
63
|
+
def files_for(klass)
|
64
|
+
locations_for(klass).map(&:path).to_set
|
65
|
+
end
|
65
66
|
|
66
|
-
|
67
|
-
|
67
|
+
def locations_for(klass)
|
68
|
+
@class_files.fetch(klass, Set.new)
|
69
|
+
end
|
68
70
|
end
|
69
71
|
end
|
70
72
|
end
|