rbi 0.1.14 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,320 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ class Type
6
+ class Error < RBI::Error; end
7
+
8
+ class << self
9
+ sig { params(string: String).returns(Type) }
10
+ def parse_string(string)
11
+ result = Prism.parse(string)
12
+ unless result.success?
13
+ raise Error, result.errors.map { |e| "#{e.message}." }.join(" ")
14
+ end
15
+
16
+ node = result.value
17
+ raise Error, "Expected a type expression, got `#{node.class}`" unless node.is_a?(Prism::ProgramNode)
18
+ raise Error, "Expected a type expression, got nothing" if node.statements.body.empty?
19
+ raise Error, "Expected a single type expression, got `#{node.slice}`" if node.statements.body.size > 1
20
+
21
+ node = T.must(node.statements.body.first)
22
+ parse_node(node)
23
+ end
24
+
25
+ sig { params(node: Prism::Node).returns(Type) }
26
+ def parse_node(node)
27
+ case node
28
+ when Prism::ConstantReadNode, Prism::ConstantPathNode
29
+ parse_constant(node)
30
+ when Prism::CallNode
31
+ parse_call(node)
32
+ when Prism::ArrayNode
33
+ parse_tuple(node)
34
+ when Prism::HashNode, Prism::KeywordHashNode
35
+ parse_shape(node)
36
+ when Prism::ParenthesesNode
37
+ body = node.body
38
+ raise Error, "Expected exactly 1 child, got 0" unless body.is_a?(Prism::StatementsNode)
39
+
40
+ children = body.body
41
+ raise Error, "Expected exactly 1 child, got #{children.size}" unless children.size == 1
42
+
43
+ parse_node(T.must(children.first))
44
+ else
45
+ raise Error, "Unexpected node `#{node}`"
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ sig { params(node: T.any(Prism::ConstantReadNode, Prism::ConstantPathNode)).returns(Type) }
52
+ def parse_constant(node)
53
+ case node
54
+ when Prism::ConstantReadNode
55
+ # `Foo`
56
+ Type::Simple.new(node.slice)
57
+ when Prism::ConstantPathNode
58
+ if t_boolean?(node)
59
+ # `T::Boolean` or `::T::Boolean`
60
+ Type::Boolean.new
61
+ else
62
+ # `::Foo` or `::Foo::Bar`
63
+ Type::Simple.new(node.slice)
64
+ end
65
+ end
66
+ end
67
+
68
+ sig { params(node: Prism::CallNode).returns(Type) }
69
+ def parse_call(node)
70
+ recv = node.receiver
71
+
72
+ case node.name
73
+ when :void
74
+ # `void`
75
+ check_arguments_exactly!(node, 0)
76
+ return Type::Void.new if recv.nil?
77
+ when :[]
78
+ case recv
79
+ when Prism::ConstantReadNode
80
+ # `Foo[Bar]` or `Foo[Bar, Baz]`
81
+ args = check_arguments_at_least!(node, 1)
82
+ return T.unsafe(Type::Generic).new(recv.slice, *args.map { |arg| parse_node(arg) })
83
+ when Prism::ConstantPathNode
84
+ if t_class?(recv)
85
+ # `T::Class[Foo]` or `::T::Class[Foo]`
86
+ args = check_arguments_exactly!(node, 1)
87
+ return Type::Class.new(parse_node(T.must(args.first)))
88
+ else
89
+ # `::Foo[Bar]` or `::Foo[Bar, Baz]`
90
+ args = check_arguments_at_least!(node, 1)
91
+ return T.unsafe(Type::Generic).new(recv.slice, *args.map { |arg| parse_node(arg) })
92
+ end
93
+ when Prism::CallNode
94
+ # `T.class_of(Foo)[Bar]`
95
+ if t_class_of?(recv)
96
+ type_args = check_arguments_exactly!(recv, 1)
97
+ type = parse_node(T.must(type_args.first))
98
+ raise Error, "Expected a simple type, got `#{type}`" unless type.is_a?(Type::Simple)
99
+
100
+ type_param_args = check_arguments_exactly!(node, 1)
101
+ type_param = parse_node(T.must(type_param_args.first))
102
+ return Type::ClassOf.new(type, type_param)
103
+ end
104
+ end
105
+
106
+ # `something[]`
107
+ raise Error, "Unexpected expression `#{node.slice}`"
108
+ end
109
+
110
+ # `T.proc`
111
+ return parse_proc(node) if t_proc?(node)
112
+
113
+ # `Foo.nilable` or anything called on a constant that is not `::T`
114
+ raise Error, "Unexpected expression `#{node.slice}`" unless t?(recv)
115
+
116
+ case node.name
117
+ when :nilable
118
+ # `T.nilable(Foo)`
119
+ args = check_arguments_exactly!(node, 1)
120
+ type = parse_node(T.must(args.first))
121
+ Type::Nilable.new(type)
122
+ when :anything
123
+ # `T.anything`
124
+ check_arguments_exactly!(node, 0)
125
+ Type::Anything.new
126
+ when :untyped
127
+ # `T.untyped`
128
+ check_arguments_exactly!(node, 0)
129
+ Type::Untyped.new
130
+ when :noreturn
131
+ # `T.noreturn`
132
+ check_arguments_exactly!(node, 0)
133
+ Type::NoReturn.new
134
+ when :self_type
135
+ # `T.self_type`
136
+ check_arguments_exactly!(node, 0)
137
+ Type::SelfType.new
138
+ when :attached_class
139
+ # `T.attached_class`
140
+ check_arguments_exactly!(node, 0)
141
+ Type::AttachedClass.new
142
+ when :class_of
143
+ # `T.class_of(Foo)`
144
+ args = check_arguments_exactly!(node, 1)
145
+ type = parse_node(T.must(args.first))
146
+ raise Error, "Expected a simple type, got `#{type}`" unless type.is_a?(Type::Simple)
147
+
148
+ Type::ClassOf.new(type)
149
+ when :all
150
+ # `T.all(Foo, Bar)`
151
+ args = check_arguments_at_least!(node, 2)
152
+ Type::All.new(args.map { |arg| parse_node(arg) })
153
+ when :any
154
+ # `T.any(Foo, Bar)`
155
+ args = check_arguments_at_least!(node, 2)
156
+ Type::Any.new(args.map { |arg| parse_node(arg) })
157
+ when :type_parameter
158
+ # `T.type_parameter(:T)`
159
+ args = check_arguments_exactly!(node, 1)
160
+ symbol = args.first
161
+ raise Error, "Expected a symbol, got `#{symbol&.slice || "nil"}`" unless symbol.is_a?(Prism::SymbolNode)
162
+
163
+ Type::TypeParameter.new(symbol.slice.delete_prefix(":").to_sym)
164
+ else
165
+ # `T.something`
166
+ raise Error, "Unexpected expression `#{node.slice}`"
167
+ end
168
+ end
169
+
170
+ sig { params(node: Prism::ArrayNode).returns(Type) }
171
+ def parse_tuple(node)
172
+ T.unsafe(Type).tuple(*node.elements.map { |elem| parse_node(elem) })
173
+ end
174
+
175
+ sig { params(node: T.any(Prism::HashNode, Prism::KeywordHashNode)).returns(Type) }
176
+ def parse_shape(node)
177
+ hash = node.elements.map do |elem|
178
+ raise Error, "Expected key-value pair, got `#{elem.slice}`" unless elem.is_a?(Prism::AssocNode)
179
+
180
+ elem_key = elem.key
181
+ key = case elem_key
182
+ when Prism::SymbolNode
183
+ T.must(elem_key.value).to_sym
184
+ when Prism::StringNode
185
+ elem_key.content
186
+ else
187
+ raise Error, "Expected symbol or string, got `#{elem_key.slice}`"
188
+ end
189
+ [key, parse_node(elem.value)]
190
+ end.to_h
191
+ T.unsafe(Type).shape(**hash)
192
+ end
193
+
194
+ sig { params(node: Prism::CallNode).returns(Type) }
195
+ def parse_proc(node)
196
+ calls = call_chain(node).reverse
197
+ calls.pop # remove `T.`
198
+
199
+ raise Error, "Unexpected expression `#{node.slice}`" if calls.empty?
200
+
201
+ type = Type::Proc.new
202
+ calls.each do |call|
203
+ raise Error, "Unexpected expression `#{node.slice}`..." unless call.is_a?(Prism::CallNode)
204
+
205
+ case call.name
206
+ when :params
207
+ args = call.arguments&.arguments || []
208
+ hash = args.first
209
+ raise Error, "Expected hash, got `#{hash.class}`" unless hash.is_a?(Prism::KeywordHashNode)
210
+
211
+ params = hash.elements.map do |elem|
212
+ raise Error, "Expected key-value pair, got `#{elem.slice}`" unless elem.is_a?(Prism::AssocNode)
213
+
214
+ [elem.key.slice.delete_suffix(":").to_sym, parse_node(elem.value)]
215
+ end.to_h
216
+ T.unsafe(type).params(**params)
217
+ when :returns
218
+ args = check_arguments_exactly!(call, 1)
219
+ type.returns(parse_node(T.must(args.first)))
220
+ when :void
221
+ type.void
222
+ when :proc
223
+ return type
224
+ when :bind
225
+ args = check_arguments_exactly!(call, 1)
226
+ type.bind(parse_node(T.must(args.first)))
227
+ else
228
+ raise Error, "Unexpected expression `#{node.slice}`"
229
+ end
230
+ end
231
+ type
232
+ end
233
+
234
+ sig { params(node: Prism::CallNode, count: Integer).returns(T::Array[Prism::Node]) }
235
+ def check_arguments_exactly!(node, count)
236
+ args = node.arguments&.arguments || []
237
+ unless args.size == count
238
+ if count == 0
239
+ raise Error, "Expected no arguments, got #{args.size}"
240
+ elsif count == 1
241
+ raise Error, "Expected exactly 1 argument, got #{args.size}"
242
+ else
243
+ raise Error, "Expected exactly #{count} arguments, got #{args.size}"
244
+ end
245
+ end
246
+ args
247
+ end
248
+
249
+ sig { params(node: Prism::CallNode, count: Integer).returns(T::Array[Prism::Node]) }
250
+ def check_arguments_at_least!(node, count)
251
+ args = node.arguments&.arguments || []
252
+ if args.size < count
253
+ if count == 1
254
+ raise Error, "Expected at least 1 argument, got #{args.size}"
255
+ else
256
+ raise Error, "Expected at least #{count} arguments, got #{args.size}"
257
+ end
258
+ end
259
+ args
260
+ end
261
+
262
+ sig { params(node: Prism::CallNode).returns(T::Array[Prism::Node]) }
263
+ def call_chain(node)
264
+ call_chain = T.let([node], T::Array[Prism::Node])
265
+ receiver = T.let(node.receiver, T.nilable(Prism::Node))
266
+ while receiver
267
+ call_chain.prepend(receiver)
268
+ break unless receiver.is_a?(Prism::CallNode)
269
+
270
+ receiver = receiver.receiver
271
+ end
272
+ call_chain
273
+ end
274
+
275
+ sig { params(node: T.nilable(Prism::Node)).returns(T::Boolean) }
276
+ def t?(node)
277
+ case node
278
+ when Prism::ConstantReadNode
279
+ return true if node.name == :T
280
+ when Prism::ConstantPathNode
281
+ return true if node.parent.nil? && node.name == :T
282
+ end
283
+
284
+ false
285
+ end
286
+
287
+ sig { params(node: T.nilable(Prism::Node)).returns(T::Boolean) }
288
+ def t_boolean?(node)
289
+ return false unless node.is_a?(Prism::ConstantPathNode)
290
+
291
+ t?(node.parent) && node.name == :Boolean
292
+ end
293
+
294
+ sig { params(node: Prism::ConstantPathNode).returns(T::Boolean) }
295
+ def t_class?(node)
296
+ t?(node.parent) && node.name == :Class
297
+ end
298
+
299
+ sig { params(node: T.nilable(Prism::Node)).returns(T::Boolean) }
300
+ def t_class_of?(node)
301
+ return false unless node.is_a?(Prism::CallNode)
302
+
303
+ t?(node.receiver) && node.name == :class_of
304
+ end
305
+
306
+ sig { params(node: Prism::CallNode).returns(T::Boolean) }
307
+ def t_proc?(node)
308
+ chain = call_chain(node)
309
+ return false if chain.size < 2
310
+ return false unless t?(chain[0])
311
+
312
+ second = chain[1]
313
+ return false unless second.is_a?(Prism::CallNode)
314
+ return false unless second.name == :proc
315
+
316
+ true
317
+ end
318
+ end
319
+ end
320
+ end
@@ -0,0 +1,112 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RBI
5
+ class Type
6
+ class Visitor
7
+ extend T::Sig
8
+
9
+ class Error < RBI::Error; end
10
+
11
+ sig { params(node: Type).void }
12
+ def visit(node)
13
+ case node
14
+ when Type::Simple
15
+ visit_simple(node)
16
+ when Type::Void
17
+ visit_void(node)
18
+ when Type::Boolean
19
+ visit_boolean(node)
20
+ when Type::Nilable
21
+ visit_nilable(node)
22
+ when Type::Untyped
23
+ visit_untyped(node)
24
+ when Type::Generic
25
+ visit_generic(node)
26
+ when Type::Anything
27
+ visit_anything(node)
28
+ when Type::NoReturn
29
+ visit_no_return(node)
30
+ when Type::SelfType
31
+ visit_self_type(node)
32
+ when Type::AttachedClass
33
+ visit_attached_class(node)
34
+ when Type::ClassOf
35
+ visit_class_of(node)
36
+ when Type::All
37
+ visit_all(node)
38
+ when Type::Any
39
+ visit_any(node)
40
+ when Type::Tuple
41
+ visit_tuple(node)
42
+ when Type::Shape
43
+ visit_shape(node)
44
+ when Type::Proc
45
+ visit_proc(node)
46
+ when Type::TypeParameter
47
+ visit_type_parameter(node)
48
+ when Type::Class
49
+ visit_class(node)
50
+ else
51
+ raise Error, "Unhandled node: #{node.class}"
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ sig { params(type: Type::All).void }
58
+ def visit_all(type); end
59
+
60
+ sig { params(type: Type::Any).void }
61
+ def visit_any(type); end
62
+
63
+ sig { params(type: Type::Anything).void }
64
+ def visit_anything(type); end
65
+
66
+ sig { params(type: Type::AttachedClass).void }
67
+ def visit_attached_class(type); end
68
+
69
+ sig { params(type: Type::Boolean).void }
70
+ def visit_boolean(type); end
71
+
72
+ sig { params(type: Type::Class).void }
73
+ def visit_class(type); end
74
+
75
+ sig { params(type: Type::ClassOf).void }
76
+ def visit_class_of(type); end
77
+
78
+ sig { params(type: Type::Generic).void }
79
+ def visit_generic(type); end
80
+
81
+ sig { params(type: Type::Nilable).void }
82
+ def visit_nilable(type); end
83
+
84
+ sig { params(type: Type::Simple).void }
85
+ def visit_simple(type); end
86
+
87
+ sig { params(type: Type::NoReturn).void }
88
+ def visit_no_return(type); end
89
+
90
+ sig { params(type: Type::Proc).void }
91
+ def visit_proc(type); end
92
+
93
+ sig { params(type: Type::SelfType).void }
94
+ def visit_self_type(type); end
95
+
96
+ sig { params(type: Type::Void).void }
97
+ def visit_void(type); end
98
+
99
+ sig { params(type: Type::Shape).void }
100
+ def visit_shape(type); end
101
+
102
+ sig { params(type: Type::Tuple).void }
103
+ def visit_tuple(type); end
104
+
105
+ sig { params(type: Type::TypeParameter).void }
106
+ def visit_type_parameter(type); end
107
+
108
+ sig { params(type: Type::Untyped).void }
109
+ def visit_untyped(type); end
110
+ end
111
+ end
112
+ end
data/lib/rbi/version.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RBI
5
- VERSION = "0.1.14"
5
+ VERSION = "0.2.1"
6
6
  end
data/lib/rbi/visitor.rb CHANGED
@@ -19,6 +19,10 @@ module RBI
19
19
  visit_blank_line(node)
20
20
  when Comment
21
21
  visit_comment(node)
22
+ when TEnum
23
+ visit_tenum(node)
24
+ when TStruct
25
+ visit_tstruct(node)
22
26
  when Module
23
27
  visit_module(node)
24
28
  when Class
@@ -35,6 +39,8 @@ module RBI
35
39
  visit_conflict_tree(node)
36
40
  when ScopeConflict
37
41
  visit_scope_conflict(node)
42
+ when TEnumBlock
43
+ visit_tenum_block(node)
38
44
  when Tree
39
45
  visit_tree(node)
40
46
  when Const
@@ -81,16 +87,10 @@ module RBI
81
87
  visit_sig(node)
82
88
  when SigParam
83
89
  visit_sig_param(node)
84
- when TStruct
85
- visit_tstruct(node)
86
90
  when TStructConst
87
91
  visit_tstruct_const(node)
88
92
  when TStructProp
89
93
  visit_tstruct_prop(node)
90
- when TEnum
91
- visit_tenum(node)
92
- when TEnumBlock
93
- visit_tenum_block(node)
94
94
  when Helper
95
95
  visit_helper(node)
96
96
  when TypeMember
data/lib/rbi.rb CHANGED
@@ -12,20 +12,27 @@ end
12
12
 
13
13
  require "rbi/loc"
14
14
  require "rbi/model"
15
+ require "rbi/type"
15
16
  require "rbi/visitor"
16
17
  require "rbi/index"
17
18
  require "rbi/rewriters/add_sig_templates"
18
19
  require "rbi/rewriters/annotate"
19
20
  require "rbi/rewriters/deannotate"
20
21
  require "rbi/rewriters/filter_versions"
22
+ require "rbi/rewriters/flatten_singleton_methods"
23
+ require "rbi/rewriters/flatten_visibilities"
21
24
  require "rbi/rewriters/merge_trees"
25
+ require "rbi/rewriters/nest_non_public_members"
22
26
  require "rbi/rewriters/nest_singleton_methods"
23
- require "rbi/rewriters/nest_non_public_methods"
27
+ require "rbi/rewriters/nest_top_level_members"
24
28
  require "rbi/rewriters/group_nodes"
25
29
  require "rbi/rewriters/remove_known_definitions"
26
30
  require "rbi/rewriters/attr_to_methods"
27
31
  require "rbi/rewriters/sort_nodes"
28
32
  require "rbi/parser"
33
+ require "rbi/type_parser"
34
+ require "rbi/type_visitor"
29
35
  require "rbi/printer"
36
+ require "rbi/rbs_printer"
30
37
  require "rbi/formatter"
31
38
  require "rbi/version"
metadata CHANGED
@@ -1,35 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.14
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexandre Terrasa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-17 00:00:00.000000000 Z
11
+ date: 2024-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prism
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 0.18.0
20
- - - "<"
17
+ - - "~>"
21
18
  - !ruby/object:Gem::Version
22
- version: 1.0.0
19
+ version: '1.0'
23
20
  type: :runtime
24
21
  prerelease: false
25
22
  version_requirements: !ruby/object:Gem::Requirement
26
23
  requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 0.18.0
30
- - - "<"
24
+ - - "~>"
31
25
  - !ruby/object:Gem::Version
32
- version: 1.0.0
26
+ version: '1.0'
33
27
  - !ruby/object:Gem::Dependency
34
28
  name: sorbet-runtime
35
29
  requirement: !ruby/object:Gem::Requirement
@@ -61,17 +55,24 @@ files:
61
55
  - lib/rbi/model.rb
62
56
  - lib/rbi/parser.rb
63
57
  - lib/rbi/printer.rb
58
+ - lib/rbi/rbs_printer.rb
64
59
  - lib/rbi/rewriters/add_sig_templates.rb
65
60
  - lib/rbi/rewriters/annotate.rb
66
61
  - lib/rbi/rewriters/attr_to_methods.rb
67
62
  - lib/rbi/rewriters/deannotate.rb
68
63
  - lib/rbi/rewriters/filter_versions.rb
64
+ - lib/rbi/rewriters/flatten_singleton_methods.rb
65
+ - lib/rbi/rewriters/flatten_visibilities.rb
69
66
  - lib/rbi/rewriters/group_nodes.rb
70
67
  - lib/rbi/rewriters/merge_trees.rb
71
- - lib/rbi/rewriters/nest_non_public_methods.rb
68
+ - lib/rbi/rewriters/nest_non_public_members.rb
72
69
  - lib/rbi/rewriters/nest_singleton_methods.rb
70
+ - lib/rbi/rewriters/nest_top_level_members.rb
73
71
  - lib/rbi/rewriters/remove_known_definitions.rb
74
72
  - lib/rbi/rewriters/sort_nodes.rb
73
+ - lib/rbi/type.rb
74
+ - lib/rbi/type_parser.rb
75
+ - lib/rbi/type_visitor.rb
75
76
  - lib/rbi/version.rb
76
77
  - lib/rbi/visitor.rb
77
78
  homepage: https://github.com/Shopify/rbi
@@ -94,7 +95,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
95
  - !ruby/object:Gem::Version
95
96
  version: '0'
96
97
  requirements: []
97
- rubygems_version: 3.5.15
98
+ rubygems_version: 3.5.20
98
99
  signing_key:
99
100
  specification_version: 4
100
101
  summary: RBI generation framework