rbi 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3ec679e5a50e9325d794c32a93ca12eb08aff102e12b21e6476a172b8001cba
4
- data.tar.gz: 5abffaaba601923ebe58dd49e5c59aba2faf41a73ee4571b15e157c5f220297f
3
+ metadata.gz: f74d8bfd9f52c65d39357d68e286e247a48d53779397c11f310b50ca37b3b925
4
+ data.tar.gz: 0a924a9c84c508cbb70b307a1b8770f00b1c855d68c41c57e0dd74dfd1f75d86
5
5
  SHA512:
6
- metadata.gz: dfebab9782d4817841ec80c87d81ff9919df026de13614fe056bc4ca0cd9ab4546f861c230172023d8f3c185b60b1155e076c7ef22ef420421bd1203879f15b0
7
- data.tar.gz: bae1339fd94ad30d5d6997611b1ac14fc36d9119607a32f954ab2361112c5ec5c31181636409df223c190348477917cf2e27da3d2bae0551295836273e59fcbb
6
+ metadata.gz: 303c4606968022e24e65f0d9a54732431ee7c6cc315dffe592e0196e5c449a5842319d32897231f046ca8266ccaf3dc9743fd7229582988b5a590c381cf4473b
7
+ data.tar.gz: 955d836aea51639220440f984fa0a8c595c763521b84ddca73dfdd08b8b546bc5b61e3fc48a19ddd04e50a7824377cc25960816a9ac2d65454ab8821259acda8
data/Gemfile CHANGED
@@ -5,9 +5,12 @@ source "https://rubygems.org"
5
5
 
6
6
  gemspec
7
7
 
8
- group(:development) do
9
- gem('rubocop-shopify', require: false)
10
- gem('rubocop-sorbet', require: false)
11
- gem('byebug')
12
- gem('pry-byebug')
8
+ group(:development, :test) do
9
+ gem("byebug")
10
+ gem("minitest")
11
+ gem("rubocop", "~> 1.7", require: false)
12
+ gem("rubocop-shopify", require: false)
13
+ gem("rubocop-sorbet", require: false)
14
+ gem("sorbet", require: false)
15
+ gem("tapioca", require: false, github: "Shopify/tapioca", branch: "master")
13
16
  end
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
- # Rbi
1
+ # RBI generation framework
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/rbi`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ `RBI` provides a Ruby API to compose Ruby interface files consumed by Sorbet.
6
4
 
7
5
  ## Installation
8
6
 
@@ -14,7 +12,7 @@ gem 'rbi'
14
12
 
15
13
  And then execute:
16
14
 
17
- $ bundle
15
+ $ bundle install
18
16
 
19
17
  Or install it yourself as:
20
18
 
@@ -22,17 +20,47 @@ Or install it yourself as:
22
20
 
23
21
  ## Usage
24
22
 
25
- TODO: Write usage instructions here
23
+ ```rb
24
+ require "rbi"
25
+
26
+ rbi = RBI::File.new(strictness: "true") do |file|
27
+ file << RBI::Module.new("Foo") do |mod|
28
+ mod << RBI::Method.new("foo")
29
+ end
30
+ end
31
+
32
+ puts rbi.string
33
+ ```
34
+
35
+ will produce:
36
+
37
+ ```rb
38
+ # typed: true
39
+
40
+ module Foo
41
+ def foo; end
42
+ end
43
+ ```
44
+
45
+ ## Features
46
+
47
+ * RBI generation API
48
+ * RBI parsing with Whitequark
49
+ * RBI formatting
50
+ * RBI validation
51
+ * RBI merging
26
52
 
27
53
  ## Development
28
54
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
55
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
56
+
57
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
30
58
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
59
+ This repo uses itself (`rbi`) to retrieve and generate gem RBIs. You can run `dev rbi` to update local gem RBIs with RBIs from the central repo.
32
60
 
33
61
  ## Contributing
34
62
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rbi. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
63
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/rbi. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/rbi/blob/master/CODE_OF_CONDUCT.md).
36
64
 
37
65
  ## License
38
66
 
@@ -40,4 +68,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40
68
 
41
69
  ## Code of Conduct
42
70
 
43
- Everyone interacting in the Rbi projects codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/rbi/blob/master/CODE_OF_CONDUCT.md).
71
+ Everyone interacting in the Rbi project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/rbi/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,7 +1,9 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
+
3
4
  require "bundler/gem_tasks"
4
5
  require "rake/testtask"
6
+ require "rubocop/rake_task"
5
7
 
6
8
  Rake::TestTask.new(:test) do |t|
7
9
  t.libs << "test"
data/lib/rbi.rb CHANGED
@@ -1,11 +1,22 @@
1
- # typed: true
1
+ # typed: strict
2
+ # frozen_string_literal: true
2
3
 
3
4
  require "sorbet-runtime"
4
- require "thor"
5
-
6
- require "rbi/version"
7
- require "rbi/cli"
5
+ require "stringio"
8
6
 
9
7
  module RBI
10
8
  class Error < StandardError; end
11
9
  end
10
+
11
+ require "rbi/loc"
12
+ require "rbi/model"
13
+ require "rbi/visitor"
14
+ require "rbi/index"
15
+ require "rbi/rewriters/merge_trees"
16
+ require "rbi/rewriters/nest_singleton_methods"
17
+ require "rbi/rewriters/nest_non_public_methods"
18
+ require "rbi/rewriters/group_nodes"
19
+ require "rbi/rewriters/sort_nodes"
20
+ require "rbi/parser"
21
+ require "rbi/printer"
22
+ require "rbi/version"
data/lib/rbi/index.rb ADDED
@@ -0,0 +1,186 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ class Index < Visitor
6
+ extend T::Sig
7
+ include T::Enumerable
8
+
9
+ sig { params(node: Node).returns(Index) }
10
+ def self.index(*node)
11
+ index = Index.new
12
+ index.visit_all(node)
13
+ index
14
+ end
15
+
16
+ sig { void }
17
+ def initialize
18
+ super()
19
+ @index = T.let({}, T::Hash[String, T::Array[Node]])
20
+ end
21
+
22
+ sig { returns(T::Array[String]) }
23
+ def keys
24
+ @index.keys
25
+ end
26
+
27
+ sig { params(id: String).returns(T::Array[Node]) }
28
+ def [](id)
29
+ @index[id] ||= []
30
+ end
31
+
32
+ sig { params(node: T.all(Indexable, Node)).void }
33
+ def index(node)
34
+ node.index_ids.each { |id| self[id] << node }
35
+ end
36
+
37
+ sig { override.params(node: T.nilable(Node)).void }
38
+ def visit(node)
39
+ return unless node
40
+
41
+ case node
42
+ when Scope
43
+ index(node)
44
+ visit_all(node.nodes)
45
+ when Tree
46
+ visit_all(node.nodes)
47
+ when Indexable
48
+ index(node)
49
+ end
50
+ end
51
+ end
52
+
53
+ class Tree
54
+ extend T::Sig
55
+
56
+ sig { returns(Index) }
57
+ def index
58
+ Index.index(self)
59
+ end
60
+ end
61
+
62
+ # A Node that can be refered to by a unique ID inside an index
63
+ module Indexable
64
+ extend T::Sig
65
+ extend T::Helpers
66
+
67
+ interface!
68
+
69
+ # Unique IDs that refer to this node.
70
+ #
71
+ # Some nodes can have multiple ids, for example an attribute accessor matches the ID of the
72
+ # getter and the setter.
73
+ sig { abstract.returns(T::Array[String]) }
74
+ def index_ids; end
75
+ end
76
+
77
+ class Scope
78
+ extend T::Sig
79
+ include Indexable
80
+
81
+ sig { override.returns(T::Array[String]) }
82
+ def index_ids
83
+ [fully_qualified_name]
84
+ end
85
+ end
86
+
87
+ class Const
88
+ extend T::Sig
89
+ include Indexable
90
+
91
+ sig { override.returns(T::Array[String]) }
92
+ def index_ids
93
+ [fully_qualified_name]
94
+ end
95
+ end
96
+
97
+ class Attr
98
+ extend T::Sig
99
+ include Indexable
100
+
101
+ sig { override.returns(T::Array[String]) }
102
+ def index_ids
103
+ fully_qualified_names
104
+ end
105
+ end
106
+
107
+ class Method
108
+ extend T::Sig
109
+ include Indexable
110
+
111
+ sig { override.returns(T::Array[String]) }
112
+ def index_ids
113
+ [fully_qualified_name]
114
+ end
115
+ end
116
+
117
+ class Include
118
+ extend T::Sig
119
+ include Indexable
120
+
121
+ sig { override.returns(T::Array[String]) }
122
+ def index_ids
123
+ names.map { |name| "#{parent_scope&.fully_qualified_name}.include(#{name})" }
124
+ end
125
+ end
126
+
127
+ class Extend
128
+ extend T::Sig
129
+ include Indexable
130
+
131
+ sig { override.returns(T::Array[String]) }
132
+ def index_ids
133
+ names.map { |name| "#{parent_scope&.fully_qualified_name}.extend(#{name})" }
134
+ end
135
+ end
136
+
137
+ class MixesInClassMethods
138
+ extend T::Sig
139
+ include Indexable
140
+
141
+ sig { override.returns(T::Array[String]) }
142
+ def index_ids
143
+ names.map { |name| "#{parent_scope&.fully_qualified_name}.mixes_in_class_method(#{name})" }
144
+ end
145
+ end
146
+
147
+ class Helper
148
+ extend T::Sig
149
+ include Indexable
150
+
151
+ sig { override.returns(T::Array[String]) }
152
+ def index_ids
153
+ [to_s]
154
+ end
155
+ end
156
+
157
+ class TStructConst
158
+ extend T::Sig
159
+ include Indexable
160
+
161
+ sig { override.returns(T::Array[String]) }
162
+ def index_ids
163
+ fully_qualified_names
164
+ end
165
+ end
166
+
167
+ class TStructProp
168
+ extend T::Sig
169
+ include Indexable
170
+
171
+ sig { override.returns(T::Array[String]) }
172
+ def index_ids
173
+ fully_qualified_names
174
+ end
175
+ end
176
+
177
+ class TEnumBlock
178
+ extend T::Sig
179
+ include Indexable
180
+
181
+ sig { override.returns(T::Array[String]) }
182
+ def index_ids
183
+ [to_s]
184
+ end
185
+ end
186
+ end
data/lib/rbi/loc.rb ADDED
@@ -0,0 +1,36 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ class Loc
6
+ extend T::Sig
7
+
8
+ sig { returns(T.nilable(String)) }
9
+ attr_reader :file
10
+
11
+ sig { returns(T.nilable(Integer)) }
12
+ attr_reader :begin_line, :end_line, :begin_column, :end_column
13
+
14
+ sig do
15
+ params(
16
+ file: T.nilable(String),
17
+ begin_line: T.nilable(Integer),
18
+ end_line: T.nilable(Integer),
19
+ begin_column: T.nilable(Integer),
20
+ end_column: T.nilable(Integer)
21
+ ).void
22
+ end
23
+ def initialize(file: nil, begin_line: nil, end_line: nil, begin_column: nil, end_column: nil)
24
+ @file = file
25
+ @begin_line = begin_line
26
+ @end_line = end_line
27
+ @begin_column = begin_column
28
+ @end_column = end_column
29
+ end
30
+
31
+ sig { returns(String) }
32
+ def to_s
33
+ "#{file}:#{begin_line}:#{begin_column}-#{end_line}:#{end_column}"
34
+ end
35
+ end
36
+ end
data/lib/rbi/model.rb ADDED
@@ -0,0 +1,879 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ class Node
6
+ extend T::Sig
7
+ extend T::Helpers
8
+
9
+ abstract!
10
+
11
+ sig { returns(T.nilable(Tree)) }
12
+ attr_accessor :parent_tree
13
+
14
+ sig { returns(T.nilable(Loc)) }
15
+ attr_accessor :loc
16
+
17
+ sig { params(loc: T.nilable(Loc)).void }
18
+ def initialize(loc: nil)
19
+ @parent_tree = nil
20
+ @loc = loc
21
+ end
22
+
23
+ sig { void }
24
+ def detach
25
+ tree = parent_tree
26
+ return unless tree
27
+ tree.nodes.delete(self)
28
+ self.parent_tree = nil
29
+ end
30
+
31
+ sig { params(node: Node).void }
32
+ def replace(node)
33
+ tree = parent_tree
34
+ raise unless tree
35
+ index = tree.nodes.index(self)
36
+ raise unless index
37
+ tree.nodes[index] = node
38
+ node.parent_tree = tree
39
+ self.parent_tree = nil
40
+ end
41
+
42
+ sig { returns(T.nilable(Scope)) }
43
+ def parent_scope
44
+ parent = T.let(parent_tree, T.nilable(Tree))
45
+ parent = parent.parent_tree until parent.is_a?(Scope) || parent.nil?
46
+ parent
47
+ end
48
+ end
49
+
50
+ class Comment < Node
51
+ extend T::Helpers
52
+
53
+ sig { returns(String) }
54
+ attr_accessor :text
55
+
56
+ sig { params(text: String, loc: T.nilable(Loc)).void }
57
+ def initialize(text, loc: nil)
58
+ super(loc: loc)
59
+ @text = text
60
+ end
61
+
62
+ sig { params(other: Object).returns(T::Boolean) }
63
+ def ==(other)
64
+ return false unless other.is_a?(Comment)
65
+ text == other.text
66
+ end
67
+ end
68
+
69
+ class NodeWithComments < Node
70
+ extend T::Sig
71
+ extend T::Helpers
72
+
73
+ abstract!
74
+
75
+ sig { returns(T::Array[Comment]) }
76
+ attr_accessor :comments
77
+
78
+ sig { params(loc: T.nilable(Loc), comments: T::Array[Comment]).void }
79
+ def initialize(loc: nil, comments: [])
80
+ super(loc: loc)
81
+ @comments = comments
82
+ end
83
+ end
84
+
85
+ class Tree < NodeWithComments
86
+ extend T::Sig
87
+
88
+ sig { returns(T::Array[Node]) }
89
+ attr_reader :nodes
90
+
91
+ sig do
92
+ params(
93
+ loc: T.nilable(Loc),
94
+ comments: T::Array[Comment],
95
+ block: T.nilable(T.proc.params(tree: Tree).void)
96
+ ).void
97
+ end
98
+ def initialize(loc: nil, comments: [], &block)
99
+ super(loc: loc, comments: comments)
100
+ @nodes = T.let([], T::Array[Node])
101
+ block&.call(self)
102
+ end
103
+
104
+ sig { params(node: Node).void }
105
+ def <<(node)
106
+ node.parent_tree = self
107
+ @nodes << node
108
+ end
109
+
110
+ sig { returns(T::Boolean) }
111
+ def empty?
112
+ nodes.empty?
113
+ end
114
+ end
115
+
116
+ class File
117
+ extend T::Sig
118
+
119
+ sig { returns(Tree) }
120
+ attr_reader :root
121
+
122
+ sig { returns(T.nilable(String)) }
123
+ attr_reader :strictness
124
+
125
+ sig { returns(T::Array[Comment]) }
126
+ attr_accessor :comments
127
+
128
+ sig do
129
+ params(
130
+ strictness: T.nilable(String),
131
+ comments: T::Array[Comment],
132
+ block: T.nilable(T.proc.params(mod: File).void)
133
+ ).void
134
+ end
135
+ def initialize(strictness: nil, comments: [], &block)
136
+ @root = T.let(Tree.new, Tree)
137
+ @strictness = strictness
138
+ @comments = comments
139
+ block&.call(self)
140
+ end
141
+
142
+ sig { params(node: Node).void }
143
+ def <<(node)
144
+ @root << node
145
+ end
146
+ end
147
+
148
+ # Scopes
149
+
150
+ class Scope < Tree
151
+ extend T::Helpers
152
+
153
+ abstract!
154
+
155
+ sig { abstract.returns(String) }
156
+ def fully_qualified_name; end
157
+
158
+ sig { override.returns(String) }
159
+ def to_s
160
+ fully_qualified_name
161
+ end
162
+ end
163
+
164
+ class Module < Scope
165
+ extend T::Sig
166
+
167
+ sig { returns(String) }
168
+ attr_accessor :name
169
+
170
+ sig do
171
+ params(
172
+ name: String,
173
+ loc: T.nilable(Loc),
174
+ comments: T::Array[Comment],
175
+ block: T.nilable(T.proc.params(mod: Module).void)
176
+ ).void
177
+ end
178
+ def initialize(name, loc: nil, comments: [], &block)
179
+ super(loc: loc, comments: comments) {}
180
+ @name = name
181
+ block&.call(self)
182
+ end
183
+
184
+ sig { override.returns(String) }
185
+ def fully_qualified_name
186
+ return name if name.start_with?("::")
187
+ "#{parent_scope&.fully_qualified_name}::#{name}"
188
+ end
189
+ end
190
+
191
+ class Class < Scope
192
+ extend T::Sig
193
+
194
+ sig { returns(String) }
195
+ attr_accessor :name
196
+
197
+ sig { returns(T.nilable(String)) }
198
+ attr_accessor :superclass_name
199
+
200
+ sig do
201
+ params(
202
+ name: String,
203
+ superclass_name: T.nilable(String),
204
+ loc: T.nilable(Loc),
205
+ comments: T::Array[Comment],
206
+ block: T.nilable(T.proc.params(klass: Class).void)
207
+ ).void
208
+ end
209
+ def initialize(name, superclass_name: nil, loc: nil, comments: [], &block)
210
+ super(loc: loc, comments: comments) {}
211
+ @name = name
212
+ @superclass_name = superclass_name
213
+ block&.call(self)
214
+ end
215
+
216
+ sig { override.returns(String) }
217
+ def fully_qualified_name
218
+ return name if name.start_with?("::")
219
+ "#{parent_scope&.fully_qualified_name}::#{name}"
220
+ end
221
+ end
222
+
223
+ class SingletonClass < Scope
224
+ extend T::Sig
225
+
226
+ sig do
227
+ params(
228
+ loc: T.nilable(Loc),
229
+ comments: T::Array[Comment],
230
+ block: T.nilable(T.proc.params(klass: SingletonClass).void)
231
+ ).void
232
+ end
233
+ def initialize(loc: nil, comments: [], &block)
234
+ super(loc: loc, comments: comments) {}
235
+ block&.call(self)
236
+ end
237
+
238
+ sig { override.returns(String) }
239
+ def fully_qualified_name
240
+ "#{parent_scope&.fully_qualified_name}::<self>"
241
+ end
242
+ end
243
+
244
+ # Consts
245
+
246
+ class Const < NodeWithComments
247
+ extend T::Sig
248
+
249
+ sig { returns(String) }
250
+ attr_reader :name, :value
251
+
252
+ sig { params(name: String, value: String, loc: T.nilable(Loc), comments: T::Array[Comment]).void }
253
+ def initialize(name, value, loc: nil, comments: [])
254
+ super(loc: loc, comments: comments)
255
+ @name = name
256
+ @value = value
257
+ end
258
+
259
+ sig { returns(String) }
260
+ def fully_qualified_name
261
+ return name if name.start_with?("::")
262
+ "#{parent_scope&.fully_qualified_name}::#{name}"
263
+ end
264
+
265
+ sig { override.returns(String) }
266
+ def to_s
267
+ fully_qualified_name
268
+ end
269
+ end
270
+
271
+ # Attributes
272
+
273
+ class Attr < NodeWithComments
274
+ extend T::Sig
275
+ extend T::Helpers
276
+
277
+ abstract!
278
+
279
+ sig { returns(T::Array[Symbol]) }
280
+ attr_accessor :names
281
+
282
+ sig { returns(Visibility) }
283
+ attr_accessor :visibility
284
+
285
+ sig { returns(T::Array[Sig]) }
286
+ attr_reader :sigs
287
+
288
+ sig do
289
+ params(
290
+ name: Symbol,
291
+ names: Symbol,
292
+ visibility: Visibility,
293
+ sigs: T::Array[Sig],
294
+ loc: T.nilable(Loc),
295
+ comments: T::Array[Comment]
296
+ ).void
297
+ end
298
+ def initialize(name, *names, visibility: Visibility::Public, sigs: [], loc: nil, comments: [])
299
+ super(loc: loc, comments: comments)
300
+ @names = T.let([name, *names], T::Array[Symbol])
301
+ @visibility = visibility
302
+ @sigs = sigs
303
+ end
304
+
305
+ sig { abstract.returns(T::Array[String]) }
306
+ def fully_qualified_names; end
307
+ end
308
+
309
+ class AttrAccessor < Attr
310
+ extend T::Sig
311
+
312
+ sig { override.returns(T::Array[String]) }
313
+ def fully_qualified_names
314
+ parent_name = parent_scope&.fully_qualified_name
315
+ names.flat_map { |name| ["#{parent_name}##{name}", "#{parent_name}##{name}="] }
316
+ end
317
+
318
+ sig { override.returns(String) }
319
+ def to_s
320
+ symbols = names.map { |name| ":#{name}" }.join(", ")
321
+ "#{parent_scope&.fully_qualified_name}.attr_accessor(#{symbols})"
322
+ end
323
+ end
324
+
325
+ class AttrReader < Attr
326
+ extend T::Sig
327
+
328
+ sig { override.returns(T::Array[String]) }
329
+ def fully_qualified_names
330
+ parent_name = parent_scope&.fully_qualified_name
331
+ names.map { |name| "#{parent_name}##{name}" }
332
+ end
333
+
334
+ sig { override.returns(String) }
335
+ def to_s
336
+ symbols = names.map { |name| ":#{name}" }.join(", ")
337
+ "#{parent_scope&.fully_qualified_name}.attr_reader(#{symbols})"
338
+ end
339
+ end
340
+
341
+ class AttrWriter < Attr
342
+ extend T::Sig
343
+
344
+ sig { override.returns(T::Array[String]) }
345
+ def fully_qualified_names
346
+ parent_name = parent_scope&.fully_qualified_name
347
+ names.map { |name| "#{parent_name}##{name}=" }
348
+ end
349
+
350
+ sig { override.returns(String) }
351
+ def to_s
352
+ symbols = names.map { |name| ":#{name}" }.join(", ")
353
+ "#{parent_scope&.fully_qualified_name}.attr_writer(#{symbols})"
354
+ end
355
+ end
356
+
357
+ # Methods and args
358
+
359
+ class Method < NodeWithComments
360
+ extend T::Sig
361
+
362
+ sig { returns(String) }
363
+ attr_accessor :name
364
+
365
+ sig { returns(T::Array[Param]) }
366
+ attr_reader :params
367
+
368
+ sig { returns(T::Boolean) }
369
+ attr_accessor :is_singleton
370
+
371
+ sig { returns(Visibility) }
372
+ attr_accessor :visibility
373
+
374
+ sig { returns(T::Array[Sig]) }
375
+ attr_accessor :sigs
376
+
377
+ sig do
378
+ params(
379
+ name: String,
380
+ params: T::Array[Param],
381
+ is_singleton: T::Boolean,
382
+ visibility: Visibility,
383
+ sigs: T::Array[Sig],
384
+ loc: T.nilable(Loc),
385
+ comments: T::Array[Comment],
386
+ block: T.nilable(T.proc.params(mod: Method).void)
387
+ ).void
388
+ end
389
+ def initialize(
390
+ name,
391
+ params: [],
392
+ is_singleton: false,
393
+ visibility: Visibility::Public,
394
+ sigs: [],
395
+ loc: nil,
396
+ comments: [],
397
+ &block
398
+ )
399
+ super(loc: loc, comments: comments)
400
+ @name = name
401
+ @params = params
402
+ @is_singleton = is_singleton
403
+ @visibility = visibility
404
+ @sigs = sigs
405
+ block&.call(self)
406
+ end
407
+
408
+ sig { params(param: Param).void }
409
+ def <<(param)
410
+ @params << param
411
+ end
412
+
413
+ sig { returns(String) }
414
+ def fully_qualified_name
415
+ if is_singleton
416
+ "#{parent_scope&.fully_qualified_name}::#{name}"
417
+ else
418
+ "#{parent_scope&.fully_qualified_name}##{name}"
419
+ end
420
+ end
421
+
422
+ sig { override.returns(String) }
423
+ def to_s
424
+ "#{fully_qualified_name}(#{params.join(", ")})"
425
+ end
426
+ end
427
+
428
+ class Param < NodeWithComments
429
+ extend T::Sig
430
+
431
+ sig { returns(String) }
432
+ attr_reader :name
433
+
434
+ sig { params(name: String, loc: T.nilable(Loc), comments: T::Array[Comment]).void }
435
+ def initialize(name, loc: nil, comments: [])
436
+ super(loc: loc, comments: comments)
437
+ @name = name
438
+ end
439
+
440
+ sig { override.returns(String) }
441
+ def to_s
442
+ name
443
+ end
444
+
445
+ sig { params(other: T.nilable(Object)).returns(T::Boolean) }
446
+ def ==(other)
447
+ return false unless other.instance_of?(Param)
448
+ name == T.cast(other, Param).name
449
+ end
450
+ end
451
+
452
+ class OptParam < Param
453
+ extend T::Sig
454
+
455
+ sig { returns(String) }
456
+ attr_reader :value
457
+
458
+ sig { params(name: String, value: String, loc: T.nilable(Loc), comments: T::Array[Comment]).void }
459
+ def initialize(name, value, loc: nil, comments: [])
460
+ super(name, loc: loc, comments: comments)
461
+ @value = value
462
+ end
463
+
464
+ sig { params(other: T.nilable(Object)).returns(T::Boolean) }
465
+ def ==(other)
466
+ return false unless other.instance_of?(OptParam)
467
+ other = T.cast(other, OptParam)
468
+ return false unless name == other.name
469
+ value == other.value
470
+ end
471
+ end
472
+
473
+ class RestParam < Param
474
+ extend T::Sig
475
+
476
+ sig { params(other: T.nilable(Object)).returns(T::Boolean) }
477
+ def ==(other)
478
+ return false unless other.instance_of?(RestParam)
479
+ name == T.cast(other, RestParam).name
480
+ end
481
+
482
+ sig { override.returns(String) }
483
+ def to_s
484
+ "*#{name}"
485
+ end
486
+ end
487
+
488
+ class KwParam < Param
489
+ extend T::Sig
490
+
491
+ sig { override.returns(String) }
492
+ def to_s
493
+ "#{name}:"
494
+ end
495
+
496
+ sig { params(other: T.nilable(Object)).returns(T::Boolean) }
497
+ def ==(other)
498
+ return false unless other.instance_of?(KwParam)
499
+ name == T.cast(other, KwParam).name
500
+ end
501
+ end
502
+
503
+ class KwOptParam < OptParam
504
+ extend T::Sig
505
+
506
+ sig { override.returns(String) }
507
+ def to_s
508
+ "#{name}:"
509
+ end
510
+
511
+ sig { params(other: T.nilable(Object)).returns(T::Boolean) }
512
+ def ==(other)
513
+ return false unless other.instance_of?(KwOptParam)
514
+ other = T.cast(other, KwOptParam)
515
+ return false unless name == other.name
516
+ value == other.value
517
+ end
518
+ end
519
+
520
+ class KwRestParam < Param
521
+ extend T::Sig
522
+
523
+ sig { override.returns(String) }
524
+ def to_s
525
+ "**#{name}:"
526
+ end
527
+
528
+ sig { params(other: T.nilable(Object)).returns(T::Boolean) }
529
+ def ==(other)
530
+ return false unless other.instance_of?(KwRestParam)
531
+ name == T.cast(other, KwRestParam).name
532
+ end
533
+ end
534
+
535
+ class BlockParam < Param
536
+ extend T::Sig
537
+
538
+ sig { override.returns(String) }
539
+ def to_s
540
+ "&#{name}"
541
+ end
542
+
543
+ sig { params(other: T.nilable(Object)).returns(T::Boolean) }
544
+ def ==(other)
545
+ return false unless other.instance_of?(BlockParam)
546
+ name == T.cast(other, BlockParam).name
547
+ end
548
+ end
549
+
550
+ # Mixins
551
+
552
+ class Mixin < NodeWithComments
553
+ extend T::Sig
554
+ extend T::Helpers
555
+
556
+ abstract!
557
+
558
+ sig { returns(T::Array[String]) }
559
+ attr_accessor :names
560
+
561
+ sig { params(name: String, names: String, loc: T.nilable(Loc), comments: T::Array[Comment]).void }
562
+ def initialize(name, *names, loc: nil, comments: [])
563
+ super(loc: loc, comments: comments)
564
+ @names = T.let([name, *names], T::Array[String])
565
+ end
566
+ end
567
+
568
+ class Include < Mixin
569
+ extend T::Sig
570
+
571
+ sig { override.returns(String) }
572
+ def to_s
573
+ "#{parent_scope&.fully_qualified_name}.include(#{names.join(", ")})"
574
+ end
575
+ end
576
+
577
+ class Extend < Mixin
578
+ extend T::Sig
579
+
580
+ sig { override.returns(String) }
581
+ def to_s
582
+ "#{parent_scope&.fully_qualified_name}.extend(#{names.join(", ")})"
583
+ end
584
+ end
585
+
586
+ # Visibility
587
+
588
+ class Visibility < Node
589
+ extend T::Sig
590
+ extend T::Helpers
591
+
592
+ abstract!
593
+
594
+ sig { returns(Symbol) }
595
+ attr_reader :visibility
596
+
597
+ sig { params(visibility: Symbol, loc: T.nilable(Loc)).void }
598
+ def initialize(visibility, loc: nil)
599
+ super(loc: loc)
600
+ @visibility = visibility
601
+ end
602
+
603
+ sig { params(other: Visibility).returns(T::Boolean) }
604
+ def ==(other)
605
+ visibility == other.visibility
606
+ end
607
+
608
+ Public = T.let(Visibility.new(:public), Visibility)
609
+ Protected = T.let(Visibility.new(:protected), Visibility)
610
+ Private = T.let(Visibility.new(:private), Visibility)
611
+ end
612
+
613
+ # Sorbet's sigs
614
+
615
+ class Sig < Node
616
+ extend T::Sig
617
+
618
+ sig { returns(T::Array[SigParam]) }
619
+ attr_reader :params
620
+
621
+ sig { returns(T.nilable(String)) }
622
+ attr_accessor :return_type
623
+
624
+ sig { returns(T::Boolean) }
625
+ attr_accessor :is_abstract, :is_override, :is_overridable
626
+
627
+ sig { returns(T::Array[String]) }
628
+ attr_reader :type_params
629
+
630
+ sig { returns(T.nilable(Symbol)) }
631
+ attr_accessor :checked
632
+
633
+ sig do
634
+ params(
635
+ params: T::Array[SigParam],
636
+ return_type: T.nilable(String),
637
+ is_abstract: T::Boolean,
638
+ is_override: T::Boolean,
639
+ is_overridable: T::Boolean,
640
+ type_params: T::Array[String],
641
+ checked: T.nilable(Symbol),
642
+ loc: T.nilable(Loc)
643
+ ).void
644
+ end
645
+ def initialize(
646
+ params: [],
647
+ return_type: nil,
648
+ is_abstract: false,
649
+ is_override: false,
650
+ is_overridable: false,
651
+ type_params: [],
652
+ checked: nil,
653
+ loc: nil
654
+ )
655
+ super(loc: loc)
656
+ @params = params
657
+ @return_type = return_type
658
+ @is_abstract = is_abstract
659
+ @is_override = is_override
660
+ @is_overridable = is_overridable
661
+ @type_params = type_params
662
+ @checked = checked
663
+ end
664
+
665
+ sig { params(param: SigParam).void }
666
+ def <<(param)
667
+ @params << param
668
+ end
669
+
670
+ sig { params(other: Object).returns(T::Boolean) }
671
+ def ==(other)
672
+ return false unless other.is_a?(Sig)
673
+ params == other.params && return_type == other.return_type && is_abstract == other.is_abstract &&
674
+ is_override == other.is_override && is_overridable == other.is_overridable &&
675
+ type_params == other.type_params && checked == other.checked
676
+ end
677
+ end
678
+
679
+ class SigParam < Node
680
+ extend T::Sig
681
+
682
+ sig { returns(String) }
683
+ attr_reader :name, :type
684
+
685
+ sig { params(name: String, type: String, loc: T.nilable(Loc)).void }
686
+ def initialize(name, type, loc: nil)
687
+ super(loc: loc)
688
+ @name = name
689
+ @type = type
690
+ end
691
+
692
+ sig { params(other: Object).returns(T::Boolean) }
693
+ def ==(other)
694
+ other.is_a?(SigParam) && name == other.name && type == other.type
695
+ end
696
+ end
697
+
698
+ # Sorbet's T::Struct
699
+
700
+ class TStruct < Class
701
+ extend T::Sig
702
+
703
+ sig do
704
+ params(
705
+ name: String,
706
+ loc: T.nilable(Loc),
707
+ comments: T::Array[Comment],
708
+ block: T.nilable(T.proc.params(klass: TStruct).void)
709
+ ).void
710
+ end
711
+ def initialize(name, loc: nil, comments: [], &block)
712
+ super(name, superclass_name: "::T::Struct", loc: loc, comments: comments) {}
713
+ block&.call(self)
714
+ end
715
+ end
716
+
717
+ class TStructField < NodeWithComments
718
+ extend T::Sig
719
+ extend T::Helpers
720
+
721
+ abstract!
722
+
723
+ sig { returns(String) }
724
+ attr_accessor :name, :type
725
+
726
+ sig { returns(T.nilable(String)) }
727
+ attr_accessor :default
728
+
729
+ sig do
730
+ params(
731
+ name: String,
732
+ type: String,
733
+ default: T.nilable(String),
734
+ loc: T.nilable(Loc),
735
+ comments: T::Array[Comment]
736
+ ).void
737
+ end
738
+ def initialize(name, type, default: nil, loc: nil, comments: [])
739
+ super(loc: loc, comments: comments)
740
+ @name = name
741
+ @type = type
742
+ @default = default
743
+ end
744
+
745
+ sig { abstract.returns(T::Array[String]) }
746
+ def fully_qualified_names; end
747
+ end
748
+
749
+ class TStructConst < TStructField
750
+ extend T::Sig
751
+
752
+ sig { override.returns(T::Array[String]) }
753
+ def fully_qualified_names
754
+ parent_name = parent_scope&.fully_qualified_name
755
+ ["#{parent_name}##{name}"]
756
+ end
757
+
758
+ sig { override.returns(String) }
759
+ def to_s
760
+ "#{parent_scope&.fully_qualified_name}.const(:#{name})"
761
+ end
762
+ end
763
+
764
+ class TStructProp < TStructField
765
+ extend T::Sig
766
+
767
+ sig { override.returns(T::Array[String]) }
768
+ def fully_qualified_names
769
+ parent_name = parent_scope&.fully_qualified_name
770
+ ["#{parent_name}##{name}", "#{parent_name}##{name}="]
771
+ end
772
+
773
+ sig { override.returns(String) }
774
+ def to_s
775
+ "#{parent_scope&.fully_qualified_name}.prop(:#{name})"
776
+ end
777
+ end
778
+
779
+ # Sorbet's T::Enum
780
+
781
+ class TEnum < Class
782
+ extend T::Sig
783
+
784
+ sig do
785
+ params(
786
+ name: String,
787
+ loc: T.nilable(Loc),
788
+ comments: T::Array[Comment],
789
+ block: T.nilable(T.proc.params(klass: TEnum).void)
790
+ ).void
791
+ end
792
+ def initialize(name, loc: nil, comments: [], &block)
793
+ super(name, superclass_name: "::T::Enum", loc: loc, comments: comments) {}
794
+ block&.call(self)
795
+ end
796
+ end
797
+
798
+ class TEnumBlock < NodeWithComments
799
+ extend T::Sig
800
+
801
+ sig { returns(T::Array[String]) }
802
+ attr_reader :names
803
+
804
+ sig { params(names: T::Array[String], loc: T.nilable(Loc), comments: T::Array[Comment]).void }
805
+ def initialize(names = [], loc: nil, comments: [])
806
+ super(loc: loc, comments: comments)
807
+ @names = names
808
+ end
809
+
810
+ sig { returns(T::Boolean) }
811
+ def empty?
812
+ names.empty?
813
+ end
814
+
815
+ sig { params(name: String).void }
816
+ def <<(name)
817
+ @names << name
818
+ end
819
+
820
+ sig { override.returns(String) }
821
+ def to_s
822
+ "#{parent_scope&.fully_qualified_name}.enums"
823
+ end
824
+ end
825
+
826
+ # Sorbet's misc.
827
+
828
+ class Helper < NodeWithComments
829
+ extend T::Helpers
830
+
831
+ sig { returns(String) }
832
+ attr_reader :name
833
+
834
+ sig { params(name: String, loc: T.nilable(Loc), comments: T::Array[Comment]).void }
835
+ def initialize(name, loc: nil, comments: [])
836
+ super(loc: loc, comments: comments)
837
+ @name = name
838
+ end
839
+
840
+ sig { override.returns(String) }
841
+ def to_s
842
+ "#{parent_scope&.fully_qualified_name}.#{name}!"
843
+ end
844
+ end
845
+
846
+ class TypeMember < NodeWithComments
847
+ extend T::Sig
848
+
849
+ sig { returns(String) }
850
+ attr_reader :name, :value
851
+
852
+ sig { params(name: String, value: String, loc: T.nilable(Loc), comments: T::Array[Comment]).void }
853
+ def initialize(name, value, loc: nil, comments: [])
854
+ super(loc: loc, comments: comments)
855
+ @name = name
856
+ @value = value
857
+ end
858
+
859
+ sig { returns(String) }
860
+ def fully_qualified_name
861
+ return name if name.start_with?("::")
862
+ "#{parent_scope&.fully_qualified_name}::#{name}"
863
+ end
864
+
865
+ sig { override.returns(String) }
866
+ def to_s
867
+ fully_qualified_name
868
+ end
869
+ end
870
+
871
+ class MixesInClassMethods < Mixin
872
+ extend T::Sig
873
+
874
+ sig { override.returns(String) }
875
+ def to_s
876
+ "#{parent_scope&.fully_qualified_name}.mixes_in_class_methods(#{names.join(", ")})"
877
+ end
878
+ end
879
+ end