tapioca 0.4.18 → 0.4.23
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/Gemfile +13 -14
- data/exe/tapioca +2 -0
- data/lib/tapioca/cli/main.rb +11 -1
- data/lib/tapioca/compilers/dsl/active_job.rb +79 -0
- data/lib/tapioca/compilers/dsl/protobuf.rb +132 -16
- data/lib/tapioca/compilers/requires_compiler.rb +1 -1
- data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +261 -362
- data/lib/tapioca/core_ext/string.rb +18 -0
- data/lib/tapioca/gemfile.rb +24 -4
- data/lib/tapioca/generator.rb +82 -29
- data/lib/tapioca/generic_type_registry.rb +58 -6
- data/lib/tapioca/internal.rb +8 -0
- data/lib/tapioca/rbi/model.rb +405 -0
- data/lib/tapioca/rbi/printer.rb +410 -0
- data/lib/tapioca/rbi/rewriters/group_nodes.rb +106 -0
- data/lib/tapioca/rbi/rewriters/nest_non_public_methods.rb +65 -0
- data/lib/tapioca/rbi/rewriters/nest_singleton_methods.rb +42 -0
- data/lib/tapioca/rbi/rewriters/sort_nodes.rb +82 -0
- data/lib/tapioca/rbi/visitor.rb +21 -0
- data/lib/tapioca/sorbet_ext/fixed_hash_patch.rb +20 -0
- data/lib/tapioca/version.rb +1 -1
- metadata +13 -3
@@ -0,0 +1,18 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
class String
|
5
|
+
extend T::Sig
|
6
|
+
|
7
|
+
sig { returns(String) }
|
8
|
+
def underscore
|
9
|
+
return self unless /[A-Z-]|::/.match?(self)
|
10
|
+
|
11
|
+
word = to_s.gsub("::", "/")
|
12
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
13
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
14
|
+
word.tr!("-", "_")
|
15
|
+
word.downcase!
|
16
|
+
word
|
17
|
+
end
|
18
|
+
end
|
data/lib/tapioca/gemfile.rb
CHANGED
@@ -108,8 +108,14 @@ module Tapioca
|
|
108
108
|
|
109
109
|
sig { returns(T::Array[Pathname]) }
|
110
110
|
def files
|
111
|
-
|
112
|
-
|
111
|
+
if default_gem?
|
112
|
+
@spec.files.map do |file|
|
113
|
+
ruby_lib_dir.join(file)
|
114
|
+
end
|
115
|
+
else
|
116
|
+
@spec.full_require_paths.flat_map do |path|
|
117
|
+
Pathname.glob((Pathname.new(path) / "**/*.rb").to_s)
|
118
|
+
end
|
113
119
|
end
|
114
120
|
end
|
115
121
|
|
@@ -125,11 +131,25 @@ module Tapioca
|
|
125
131
|
|
126
132
|
sig { params(path: String).returns(T::Boolean) }
|
127
133
|
def contains_path?(path)
|
128
|
-
|
134
|
+
if default_gem?
|
135
|
+
files.any? { |file| file.to_s == to_realpath(path) }
|
136
|
+
else
|
137
|
+
to_realpath(path).start_with?(full_gem_path) || has_parent_gemspec?(path)
|
138
|
+
end
|
129
139
|
end
|
130
140
|
|
131
141
|
private
|
132
142
|
|
143
|
+
sig { returns(T::Boolean) }
|
144
|
+
def default_gem?
|
145
|
+
@spec.respond_to?(:default_gem?) && @spec.default_gem?
|
146
|
+
end
|
147
|
+
|
148
|
+
sig { returns(Pathname) }
|
149
|
+
def ruby_lib_dir
|
150
|
+
Pathname.new(RbConfig::CONFIG["rubylibdir"])
|
151
|
+
end
|
152
|
+
|
133
153
|
sig { returns(String) }
|
134
154
|
def version_string
|
135
155
|
version = @spec.version.to_s
|
@@ -176,7 +196,7 @@ module Tapioca
|
|
176
196
|
|
177
197
|
sig { returns(T::Boolean) }
|
178
198
|
def gem_in_bundle_path?
|
179
|
-
full_gem_path.start_with?(Bundler.bundle_path.to_s)
|
199
|
+
full_gem_path.start_with?(Bundler.bundle_path.to_s, Bundler.app_cache.to_s)
|
180
200
|
end
|
181
201
|
end
|
182
202
|
end
|
data/lib/tapioca/generator.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
|
4
4
|
require 'pathname'
|
5
5
|
require 'thor'
|
6
|
+
require "tapioca/core_ext/string"
|
6
7
|
|
7
8
|
module Tapioca
|
8
9
|
class Generator < ::Thor::Shell::Color
|
@@ -120,9 +121,10 @@ module Tapioca
|
|
120
121
|
params(
|
121
122
|
requested_constants: T::Array[String],
|
122
123
|
should_verify: T::Boolean,
|
124
|
+
quiet: T::Boolean
|
123
125
|
).void
|
124
126
|
end
|
125
|
-
def build_dsl(requested_constants, should_verify: false)
|
127
|
+
def build_dsl(requested_constants, should_verify: false, quiet: false)
|
126
128
|
load_application(eager_load: requested_constants.empty?)
|
127
129
|
load_dsl_generators
|
128
130
|
|
@@ -133,7 +135,7 @@ module Tapioca
|
|
133
135
|
end
|
134
136
|
say("")
|
135
137
|
|
136
|
-
outpath = should_verify ? Dir.mktmpdir : config.outpath
|
138
|
+
outpath = should_verify ? Pathname.new(Dir.mktmpdir) : config.outpath
|
137
139
|
rbi_files_to_purge = existing_rbi_filenames(requested_constants)
|
138
140
|
|
139
141
|
compiler = Compilers::DslCompiler.new(
|
@@ -145,8 +147,18 @@ module Tapioca
|
|
145
147
|
)
|
146
148
|
|
147
149
|
compiler.run do |constant, contents|
|
148
|
-
|
149
|
-
|
150
|
+
constant_name = Module.instance_method(:name).bind(constant).call
|
151
|
+
|
152
|
+
filename = compile_dsl_rbi(
|
153
|
+
constant_name,
|
154
|
+
contents,
|
155
|
+
outpath: outpath,
|
156
|
+
quiet: should_verify || quiet
|
157
|
+
)
|
158
|
+
|
159
|
+
if filename
|
160
|
+
rbi_files_to_purge.delete(filename)
|
161
|
+
end
|
150
162
|
end
|
151
163
|
say("")
|
152
164
|
|
@@ -274,7 +286,7 @@ module Tapioca
|
|
274
286
|
def constantize(constant_names)
|
275
287
|
constant_map = constant_names.map do |name|
|
276
288
|
begin
|
277
|
-
[name, name
|
289
|
+
[name, Object.const_get(name)]
|
278
290
|
rescue NameError
|
279
291
|
[name, nil]
|
280
292
|
end
|
@@ -506,60 +518,101 @@ module Tapioca
|
|
506
518
|
end
|
507
519
|
end
|
508
520
|
|
509
|
-
sig
|
510
|
-
|
521
|
+
sig do
|
522
|
+
params(constant_name: String, contents: String, outpath: Pathname, quiet: T::Boolean)
|
523
|
+
.returns(T.nilable(Pathname))
|
524
|
+
end
|
525
|
+
def compile_dsl_rbi(constant_name, contents, outpath: config.outpath, quiet: false)
|
511
526
|
return if contents.nil?
|
512
527
|
|
513
|
-
constant_name = Module.instance_method(:name).bind(constant).call
|
514
528
|
rbi_name = constant_name.underscore + ".rbi"
|
515
529
|
filename = outpath / rbi_name
|
516
530
|
|
517
531
|
out = String.new
|
518
532
|
out << rbi_header(
|
519
533
|
"#{Config::DEFAULT_COMMAND} dsl #{constant_name}",
|
520
|
-
reason: "dynamic methods in `#{
|
534
|
+
reason: "dynamic methods in `#{constant_name}`"
|
521
535
|
)
|
522
536
|
out << contents
|
523
537
|
|
524
538
|
FileUtils.mkdir_p(File.dirname(filename))
|
525
539
|
File.write(filename, out)
|
526
|
-
|
527
|
-
|
540
|
+
|
541
|
+
unless quiet
|
542
|
+
say("Wrote: ", [:green])
|
543
|
+
say(filename)
|
544
|
+
end
|
528
545
|
|
529
546
|
filename
|
530
547
|
end
|
531
548
|
|
532
|
-
sig { params(tmp_dir: Pathname).returns(T
|
549
|
+
sig { params(tmp_dir: Pathname).returns(T::Hash[String, Symbol]) }
|
533
550
|
def verify_dsl_rbi(tmp_dir:)
|
534
|
-
|
535
|
-
new_rbis = existing_rbi_filenames([], path: tmp_dir).grep_v(/gem|shim/).sort
|
551
|
+
diff = {}
|
536
552
|
|
537
|
-
|
553
|
+
existing_rbis = rbi_files_in(config.outpath)
|
554
|
+
new_rbis = rbi_files_in(tmp_dir)
|
538
555
|
|
539
|
-
|
556
|
+
added_files = (new_rbis - existing_rbis)
|
540
557
|
|
541
|
-
|
542
|
-
|
558
|
+
added_files.each do |file|
|
559
|
+
diff[file] = :added
|
543
560
|
end
|
544
561
|
|
545
|
-
|
546
|
-
filenames = desynced_files.map { |f| f.to_s.sub!(tmp_dir.to_s, "sorbet/rbi/dsl") }.join("\n - ")
|
562
|
+
removed_files = (existing_rbis - new_rbis)
|
547
563
|
|
548
|
-
|
564
|
+
removed_files.each do |file|
|
565
|
+
diff[file] = :removed
|
549
566
|
end
|
550
567
|
|
551
|
-
|
568
|
+
common_files = (existing_rbis & new_rbis)
|
569
|
+
|
570
|
+
changed_files = common_files.map do |filename|
|
571
|
+
filename unless FileUtils.identical?(config.outpath / filename, tmp_dir / filename)
|
572
|
+
end.compact
|
573
|
+
|
574
|
+
changed_files.each do |file|
|
575
|
+
diff[file] = :changed
|
576
|
+
end
|
577
|
+
|
578
|
+
diff
|
579
|
+
end
|
580
|
+
|
581
|
+
sig { params(cause: Symbol, files: T::Array[String]).returns(String) }
|
582
|
+
def build_error_for_files(cause, files)
|
583
|
+
filenames = files.map do |file|
|
584
|
+
config.outpath / file
|
585
|
+
end.join("\n - ")
|
586
|
+
|
587
|
+
" File(s) #{cause}:\n - #{filenames}"
|
588
|
+
end
|
589
|
+
|
590
|
+
sig { params(path: Pathname).returns(T::Array[Pathname]) }
|
591
|
+
def rbi_files_in(path)
|
592
|
+
Pathname.glob(path / "**/*.rbi").map do |file|
|
593
|
+
file.relative_path_from(path)
|
594
|
+
end.sort
|
552
595
|
end
|
553
596
|
|
554
|
-
sig { params(dir:
|
597
|
+
sig { params(dir: Pathname).void }
|
555
598
|
def perform_dsl_verification(dir)
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
say(error)
|
560
|
-
exit(1)
|
561
|
-
else
|
599
|
+
diff = verify_dsl_rbi(tmp_dir: dir)
|
600
|
+
|
601
|
+
if diff.empty?
|
562
602
|
say("Nothing to do, all RBIs are up-to-date.")
|
603
|
+
else
|
604
|
+
say("RBI files are out-of-date. In your development environment, please run:", :green)
|
605
|
+
say(" `#{Config::DEFAULT_COMMAND} dsl`", [:green, :bold])
|
606
|
+
say("Once it is complete, be sure to commit and push any changes", :green)
|
607
|
+
|
608
|
+
say("")
|
609
|
+
|
610
|
+
say("Reason:", [:red])
|
611
|
+
diff.group_by(&:last).sort.each do |cause, diff_for_cause|
|
612
|
+
say(build_error_for_files(cause, diff_for_cause.map(&:first)))
|
613
|
+
end
|
614
|
+
|
615
|
+
exit(1)
|
563
616
|
end
|
564
617
|
ensure
|
565
618
|
FileUtils.remove_entry(dir)
|
@@ -51,14 +51,12 @@ module Tapioca
|
|
51
51
|
type_list = types.map { |type| T::Utils.coerce(type).name }.join(", ")
|
52
52
|
name = "#{name_of(constant)}[#{type_list}]"
|
53
53
|
|
54
|
-
# Create a
|
54
|
+
# Create a generic type with an overridden `name`
|
55
55
|
# method that returns the name we constructed above.
|
56
56
|
#
|
57
|
-
# Also, we try to memoize the
|
58
|
-
# we don't have to keep recreating
|
59
|
-
@generic_instances[name] ||= constant
|
60
|
-
clone.define_singleton_method(:name) { name }
|
61
|
-
end
|
57
|
+
# Also, we try to memoize the generic type based on the name, so that
|
58
|
+
# we don't have to keep recreating them all the time.
|
59
|
+
@generic_instances[name] ||= create_generic_type(constant, name)
|
62
60
|
end
|
63
61
|
|
64
62
|
sig do
|
@@ -94,6 +92,31 @@ module Tapioca
|
|
94
92
|
|
95
93
|
private
|
96
94
|
|
95
|
+
sig { params(constant: Module, name: String).returns(Module) }
|
96
|
+
def create_generic_type(constant, name)
|
97
|
+
generic_type = case constant
|
98
|
+
when Class
|
99
|
+
# For classes, we want to create a subclass, so that an instance of
|
100
|
+
# the generic class `Foo[Bar]` is still a `Foo`. That is:
|
101
|
+
# `Foo[Bar].new.is_a?(Foo)` should be true, which isn't the case
|
102
|
+
# if we just clone the class. But subclassing works just fine.
|
103
|
+
create_safe_subclass(constant)
|
104
|
+
else
|
105
|
+
# This can only be a module and it is fine to just clone modules
|
106
|
+
# since they can't have instances and will not have `is_a?` relationships.
|
107
|
+
# Moreover, we never `include`/`extend` any generic modules into the
|
108
|
+
# ancestor tree, so this doesn't become a problem with checking the
|
109
|
+
# instance of a class being `is_a?` of a module type.
|
110
|
+
constant.clone
|
111
|
+
end
|
112
|
+
|
113
|
+
# Let's set the `name` method to return the proper generic name
|
114
|
+
generic_type.define_singleton_method(:name) { name }
|
115
|
+
|
116
|
+
# Return the generic type we created
|
117
|
+
generic_type
|
118
|
+
end
|
119
|
+
|
97
120
|
# This method is called from intercepted calls to `type_member` and `type_template`.
|
98
121
|
# We get passed all the arguments to those methods, as well as the `T::Types::TypeVariable`
|
99
122
|
# instance generated by the Sorbet defined `type_member`/`type_template` call on `T::Generic`.
|
@@ -127,6 +150,35 @@ module Tapioca
|
|
127
150
|
)
|
128
151
|
end
|
129
152
|
|
153
|
+
sig { params(constant: Class).returns(Class) }
|
154
|
+
def create_safe_subclass(constant)
|
155
|
+
# Lookup the "inherited" class method
|
156
|
+
inherited_method = constant.method(:inherited)
|
157
|
+
# and the module that defines it
|
158
|
+
owner = inherited_method.owner
|
159
|
+
|
160
|
+
# If no one has overriden the inherited method yet, just subclass
|
161
|
+
return Class.new(constant) if Class == owner
|
162
|
+
|
163
|
+
begin
|
164
|
+
# Otherwise, some inherited method could be preventing us
|
165
|
+
# from creating subclasses, so let's override it and rescue
|
166
|
+
owner.send(:define_method, :inherited) do |s|
|
167
|
+
begin
|
168
|
+
inherited_method.call(s)
|
169
|
+
rescue
|
170
|
+
# Ignoring errors
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# return a subclass
|
175
|
+
Class.new(constant)
|
176
|
+
ensure
|
177
|
+
# Reinstate the original inherited method back.
|
178
|
+
owner.send(:define_method, :inherited, inherited_method)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
130
182
|
sig { params(constant: Module).returns(T::Hash[Integer, String]) }
|
131
183
|
def lookup_or_initialize_type_variables(constant)
|
132
184
|
@type_variables[object_id_of(constant)] ||= {}
|
data/lib/tapioca/internal.rb
CHANGED
@@ -6,12 +6,20 @@ require "tapioca/loader"
|
|
6
6
|
require "tapioca/constant_locator"
|
7
7
|
require "tapioca/generic_type_registry"
|
8
8
|
require "tapioca/sorbet_ext/generic_name_patch"
|
9
|
+
require "tapioca/sorbet_ext/fixed_hash_patch"
|
9
10
|
require "tapioca/config"
|
10
11
|
require "tapioca/config_builder"
|
11
12
|
require "tapioca/generator"
|
12
13
|
require "tapioca/cli"
|
13
14
|
require "tapioca/cli/main"
|
14
15
|
require "tapioca/gemfile"
|
16
|
+
require "tapioca/rbi/model"
|
17
|
+
require "tapioca/rbi/visitor"
|
18
|
+
require "tapioca/rbi/rewriters/nest_singleton_methods"
|
19
|
+
require "tapioca/rbi/rewriters/nest_non_public_methods"
|
20
|
+
require "tapioca/rbi/rewriters/group_nodes"
|
21
|
+
require "tapioca/rbi/rewriters/sort_nodes"
|
22
|
+
require "tapioca/rbi/printer"
|
15
23
|
require "tapioca/compilers/sorbet"
|
16
24
|
require "tapioca/compilers/requires_compiler"
|
17
25
|
require "tapioca/compilers/symbol_table_compiler"
|
@@ -0,0 +1,405 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Tapioca
|
5
|
+
module RBI
|
6
|
+
class Node
|
7
|
+
extend T::Sig
|
8
|
+
extend T::Helpers
|
9
|
+
|
10
|
+
abstract!
|
11
|
+
|
12
|
+
sig { returns(T.nilable(Tree)) }
|
13
|
+
attr_accessor :parent_tree
|
14
|
+
|
15
|
+
sig { void }
|
16
|
+
def initialize
|
17
|
+
@parent_tree = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
sig { void }
|
21
|
+
def detach
|
22
|
+
tree = parent_tree
|
23
|
+
return unless tree
|
24
|
+
tree.nodes.delete(self)
|
25
|
+
self.parent_tree = nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Tree < Node
|
30
|
+
extend T::Sig
|
31
|
+
|
32
|
+
sig { returns(T::Array[Node]) }
|
33
|
+
attr_reader :nodes
|
34
|
+
|
35
|
+
sig { void }
|
36
|
+
def initialize
|
37
|
+
super()
|
38
|
+
@nodes = T.let([], T::Array[Node])
|
39
|
+
end
|
40
|
+
|
41
|
+
sig { params(node: Node).void }
|
42
|
+
def <<(node)
|
43
|
+
node.parent_tree = self
|
44
|
+
@nodes << node
|
45
|
+
end
|
46
|
+
|
47
|
+
sig { returns(T::Boolean) }
|
48
|
+
def empty?
|
49
|
+
nodes.empty?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Scopes
|
54
|
+
|
55
|
+
class Scope < Tree
|
56
|
+
extend T::Helpers
|
57
|
+
|
58
|
+
abstract!
|
59
|
+
end
|
60
|
+
|
61
|
+
class Module < Scope
|
62
|
+
extend T::Sig
|
63
|
+
|
64
|
+
sig { returns(String) }
|
65
|
+
attr_accessor :name
|
66
|
+
|
67
|
+
sig { params(name: String).void }
|
68
|
+
def initialize(name)
|
69
|
+
super()
|
70
|
+
@name = name
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class Class < Scope
|
75
|
+
extend T::Sig
|
76
|
+
|
77
|
+
sig { returns(String) }
|
78
|
+
attr_accessor :name
|
79
|
+
|
80
|
+
sig { returns(T.nilable(String)) }
|
81
|
+
attr_accessor :superclass_name
|
82
|
+
|
83
|
+
sig { params(name: String, superclass_name: T.nilable(String)).void }
|
84
|
+
def initialize(name, superclass_name: nil)
|
85
|
+
super()
|
86
|
+
@name = name
|
87
|
+
@superclass_name = superclass_name
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class SingletonClass < Scope
|
92
|
+
extend T::Sig
|
93
|
+
|
94
|
+
sig { void }
|
95
|
+
def initialize
|
96
|
+
super()
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Consts
|
101
|
+
|
102
|
+
class Const < Node
|
103
|
+
extend T::Sig
|
104
|
+
|
105
|
+
sig { returns(String) }
|
106
|
+
attr_reader :name, :value
|
107
|
+
|
108
|
+
sig { params(name: String, value: String).void }
|
109
|
+
def initialize(name, value)
|
110
|
+
super()
|
111
|
+
@name = name
|
112
|
+
@value = value
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Methods and args
|
117
|
+
|
118
|
+
class Method < Node
|
119
|
+
extend T::Sig
|
120
|
+
|
121
|
+
sig { returns(String) }
|
122
|
+
attr_accessor :name
|
123
|
+
|
124
|
+
sig { returns(T::Array[Param]) }
|
125
|
+
attr_reader :params
|
126
|
+
|
127
|
+
sig { returns(T::Boolean) }
|
128
|
+
attr_accessor :is_singleton
|
129
|
+
|
130
|
+
sig { returns(Visibility) }
|
131
|
+
attr_accessor :visibility
|
132
|
+
|
133
|
+
sig { returns(T::Array[Sig]) }
|
134
|
+
attr_accessor :sigs
|
135
|
+
|
136
|
+
sig do
|
137
|
+
params(
|
138
|
+
name: String,
|
139
|
+
params: T::Array[Param],
|
140
|
+
is_singleton: T::Boolean,
|
141
|
+
visibility: Visibility,
|
142
|
+
sigs: T::Array[Sig]
|
143
|
+
).void
|
144
|
+
end
|
145
|
+
def initialize(name, params: [], is_singleton: false, visibility: Visibility::Public, sigs: [])
|
146
|
+
super()
|
147
|
+
@name = name
|
148
|
+
@params = params
|
149
|
+
@is_singleton = is_singleton
|
150
|
+
@visibility = visibility
|
151
|
+
@sigs = sigs
|
152
|
+
end
|
153
|
+
|
154
|
+
sig { params(param: Param).void }
|
155
|
+
def <<(param)
|
156
|
+
@params << param
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
class Param < Node
|
161
|
+
extend T::Sig
|
162
|
+
|
163
|
+
sig { returns(String) }
|
164
|
+
attr_reader :name
|
165
|
+
|
166
|
+
sig { params(name: String).void }
|
167
|
+
def initialize(name)
|
168
|
+
super()
|
169
|
+
@name = name
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
class OptParam < Param
|
174
|
+
extend T::Sig
|
175
|
+
|
176
|
+
sig { returns(String) }
|
177
|
+
attr_reader :value
|
178
|
+
|
179
|
+
sig { params(name: String, value: String).void }
|
180
|
+
def initialize(name, value)
|
181
|
+
super(name)
|
182
|
+
@value = value
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
class RestParam < Param; end
|
187
|
+
class KwParam < Param; end
|
188
|
+
class KwOptParam < OptParam; end
|
189
|
+
class KwRestParam < Param; end
|
190
|
+
class BlockParam < Param; end
|
191
|
+
|
192
|
+
# Mixins
|
193
|
+
|
194
|
+
class Mixin < Node
|
195
|
+
extend T::Sig
|
196
|
+
extend T::Helpers
|
197
|
+
|
198
|
+
abstract!
|
199
|
+
|
200
|
+
sig { returns(String) }
|
201
|
+
attr_reader :name
|
202
|
+
|
203
|
+
sig { params(name: String).void }
|
204
|
+
def initialize(name)
|
205
|
+
super()
|
206
|
+
@name = name
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
class Include < Mixin; end
|
211
|
+
class Extend < Mixin; end
|
212
|
+
|
213
|
+
# Visibility
|
214
|
+
|
215
|
+
class Visibility < Node
|
216
|
+
extend T::Sig
|
217
|
+
extend T::Helpers
|
218
|
+
|
219
|
+
abstract!
|
220
|
+
|
221
|
+
sig { returns(Symbol) }
|
222
|
+
attr_reader :visibility
|
223
|
+
|
224
|
+
sig { params(visibility: Symbol).void }
|
225
|
+
def initialize(visibility)
|
226
|
+
super()
|
227
|
+
@visibility = visibility
|
228
|
+
end
|
229
|
+
|
230
|
+
sig { returns(T::Boolean) }
|
231
|
+
def public?
|
232
|
+
visibility == :public
|
233
|
+
end
|
234
|
+
|
235
|
+
Public = T.let(Visibility.new(:public), Visibility)
|
236
|
+
Protected = T.let(Visibility.new(:protected), Visibility)
|
237
|
+
Private = T.let(Visibility.new(:private), Visibility)
|
238
|
+
end
|
239
|
+
|
240
|
+
# Sorbet's sigs
|
241
|
+
|
242
|
+
class Sig < Node
|
243
|
+
extend T::Sig
|
244
|
+
|
245
|
+
sig { returns(T::Array[SigParam]) }
|
246
|
+
attr_reader :params
|
247
|
+
|
248
|
+
sig { returns(T.nilable(String)) }
|
249
|
+
attr_accessor :return_type
|
250
|
+
|
251
|
+
sig { returns(T::Boolean) }
|
252
|
+
attr_accessor :is_abstract, :is_override, :is_overridable
|
253
|
+
|
254
|
+
sig { returns(T::Array[String]) }
|
255
|
+
attr_reader :type_params
|
256
|
+
|
257
|
+
sig do
|
258
|
+
params(
|
259
|
+
params: T::Array[SigParam],
|
260
|
+
return_type: T.nilable(String),
|
261
|
+
is_abstract: T::Boolean,
|
262
|
+
is_override: T::Boolean,
|
263
|
+
is_overridable: T::Boolean,
|
264
|
+
type_params: T::Array[String]
|
265
|
+
).void
|
266
|
+
end
|
267
|
+
def initialize(
|
268
|
+
params: [],
|
269
|
+
return_type: nil,
|
270
|
+
is_abstract: false,
|
271
|
+
is_override: false,
|
272
|
+
is_overridable: false,
|
273
|
+
type_params: []
|
274
|
+
)
|
275
|
+
super()
|
276
|
+
@params = params
|
277
|
+
@return_type = return_type
|
278
|
+
@is_abstract = is_abstract
|
279
|
+
@is_override = is_override
|
280
|
+
@is_overridable = is_overridable
|
281
|
+
@type_params = type_params
|
282
|
+
end
|
283
|
+
|
284
|
+
sig { params(param: SigParam).void }
|
285
|
+
def <<(param)
|
286
|
+
@params << param
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
class SigParam < Node
|
291
|
+
extend T::Sig
|
292
|
+
|
293
|
+
sig { returns(String) }
|
294
|
+
attr_reader :name, :type
|
295
|
+
|
296
|
+
sig { params(name: String, type: String).void }
|
297
|
+
def initialize(name, type)
|
298
|
+
super()
|
299
|
+
@name = name
|
300
|
+
@type = type
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
# Sorbet's T::Struct
|
305
|
+
|
306
|
+
class TStruct < Class
|
307
|
+
extend T::Sig
|
308
|
+
|
309
|
+
sig { params(name: String).void }
|
310
|
+
def initialize(name)
|
311
|
+
super(name, superclass_name: "::T::Struct")
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
class TStructField < Node
|
316
|
+
extend T::Sig
|
317
|
+
extend T::Helpers
|
318
|
+
|
319
|
+
abstract!
|
320
|
+
|
321
|
+
sig { returns(String) }
|
322
|
+
attr_accessor :name, :type
|
323
|
+
|
324
|
+
sig { returns(T.nilable(String)) }
|
325
|
+
attr_accessor :default
|
326
|
+
|
327
|
+
sig do
|
328
|
+
params(
|
329
|
+
name: String,
|
330
|
+
type: String,
|
331
|
+
default: T.nilable(String)
|
332
|
+
).void
|
333
|
+
end
|
334
|
+
def initialize(name, type, default: nil)
|
335
|
+
super()
|
336
|
+
@name = name
|
337
|
+
@type = type
|
338
|
+
@default = default
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
class TStructProp < TStructField; end
|
343
|
+
class TStructConst < TStructField; end
|
344
|
+
|
345
|
+
# Sorbet's T::Enum
|
346
|
+
|
347
|
+
class TEnum < Class
|
348
|
+
extend T::Sig
|
349
|
+
|
350
|
+
sig { params(name: String).void }
|
351
|
+
def initialize(name)
|
352
|
+
super(name, superclass_name: "::T::Enum")
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
class TEnumBlock < Node
|
357
|
+
extend T::Sig
|
358
|
+
|
359
|
+
sig { returns(T::Array[String]) }
|
360
|
+
attr_reader :names
|
361
|
+
|
362
|
+
sig { params(names: T::Array[String]).void }
|
363
|
+
def initialize(names = [])
|
364
|
+
super()
|
365
|
+
@names = names
|
366
|
+
end
|
367
|
+
|
368
|
+
sig { returns(T::Boolean) }
|
369
|
+
def empty?
|
370
|
+
names.empty?
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
# Sorbet's misc.
|
375
|
+
|
376
|
+
class Helper < Node
|
377
|
+
extend T::Helpers
|
378
|
+
|
379
|
+
sig { returns(String) }
|
380
|
+
attr_reader :name
|
381
|
+
|
382
|
+
sig { params(name: String).void }
|
383
|
+
def initialize(name)
|
384
|
+
super()
|
385
|
+
@name = name
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
class TypeMember < Node
|
390
|
+
extend T::Sig
|
391
|
+
|
392
|
+
sig { returns(String) }
|
393
|
+
attr_reader :name, :value
|
394
|
+
|
395
|
+
sig { params(name: String, value: String).void }
|
396
|
+
def initialize(name, value)
|
397
|
+
super()
|
398
|
+
@name = name
|
399
|
+
@value = value
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
class MixesInClassMethods < Mixin; end
|
404
|
+
end
|
405
|
+
end
|