rbi 0.1.14 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.0"
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,26 @@ 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"
30
36
  require "rbi/formatter"
31
37
  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.0
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-08-29 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
@@ -66,12 +60,18 @@ files:
66
60
  - lib/rbi/rewriters/attr_to_methods.rb
67
61
  - lib/rbi/rewriters/deannotate.rb
68
62
  - lib/rbi/rewriters/filter_versions.rb
63
+ - lib/rbi/rewriters/flatten_singleton_methods.rb
64
+ - lib/rbi/rewriters/flatten_visibilities.rb
69
65
  - lib/rbi/rewriters/group_nodes.rb
70
66
  - lib/rbi/rewriters/merge_trees.rb
71
- - lib/rbi/rewriters/nest_non_public_methods.rb
67
+ - lib/rbi/rewriters/nest_non_public_members.rb
72
68
  - lib/rbi/rewriters/nest_singleton_methods.rb
69
+ - lib/rbi/rewriters/nest_top_level_members.rb
73
70
  - lib/rbi/rewriters/remove_known_definitions.rb
74
71
  - lib/rbi/rewriters/sort_nodes.rb
72
+ - lib/rbi/type.rb
73
+ - lib/rbi/type_parser.rb
74
+ - lib/rbi/type_visitor.rb
75
75
  - lib/rbi/version.rb
76
76
  - lib/rbi/visitor.rb
77
77
  homepage: https://github.com/Shopify/rbi
@@ -94,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
96
  requirements: []
97
- rubygems_version: 3.5.15
97
+ rubygems_version: 3.5.17
98
98
  signing_key:
99
99
  specification_version: 4
100
100
  summary: RBI generation framework