rbs-inline 0.4.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,7 +3,7 @@
3
3
  module RBS
4
4
  module Inline
5
5
  module AST
6
- # CommentLines represents consecutive comments
6
+ # CommentLines represents consecutive comments, providing a mapping from locations in `#string` to a pair of a comment and its offset
7
7
  #
8
8
  # The comments construct one String.
9
9
  #
@@ -16,37 +16,34 @@ module RBS
16
16
  # And want to translate a location in the string into the location in comment1 and comment2.
17
17
  #
18
18
  class CommentLines
19
- attr_reader :comments #:: Array[[Prism::Comment, Integer]]
19
+ attr_reader :comments #: Array[Prism::Comment]
20
20
 
21
21
  # @rbs comments: Array[Prism::Comment]
22
- def initialize(comments)
23
- offsets = comments.map do |comment|
24
- comment.location.slice.index(/[^#\s]/) || 1
25
- end
26
- first_offset = offsets[0]
27
-
28
- @comments = comments.map.with_index do |comment, index|
29
- offset = offsets[index]
30
- offset = first_offset if offset > first_offset
22
+ def initialize(comments) #: void
23
+ @comments = comments
24
+ end
31
25
 
32
- [comment, offset]
33
- end
26
+ def lines #: Array[String]
27
+ comments.map {|comment| comment.location.slice }
34
28
  end
35
29
 
36
- def string #:: String
37
- comments.map {|comment, offset| comment.location.slice[offset..] }.join("\n")
30
+ def string #: String
31
+ comments.map {|comment| comment.location.slice[1..] || "" }.join("\n")
38
32
  end
39
33
 
34
+ # Translates the cursor index of `#string` into the cursor index of a specific comment object
35
+ #
40
36
  # @rbs index: Integer
41
- # @rbs returns [Prism::Comment, Integer]?
37
+ # @rbs return: [Prism::Comment, Integer]?
42
38
  def comment_location(index)
43
- comments.each do |comment, offset|
39
+ comments.each do |comment|
44
40
  comment_length = comment.location.length
45
41
 
46
- if index + offset <= comment_length
47
- return [comment, index + offset]
42
+ if index + 1 <= comment_length
43
+ return [comment, index + 1]
48
44
  else
49
- index = index - comment_length + offset - 1
45
+ index -= comment_length - 1
46
+ index -= 1 # newline
50
47
  return if index < 0
51
48
  end
52
49
  end
@@ -6,28 +6,40 @@ module RBS
6
6
  module Declarations
7
7
  module ConstantUtil
8
8
  # @rbs node: Prism::Node
9
- # @rbs returns TypeName?
9
+ # @rbs return: TypeName?
10
10
  def type_name(node)
11
11
  case node
12
12
  when Prism::ConstantReadNode, Prism::ConstantPathNode
13
13
  TypeName(node.full_name)
14
14
  end
15
15
  end
16
- end
17
16
 
18
- # @rbs! type t = ClassDecl | ModuleDecl | ConstantDecl | SingletonClassDecl
17
+ # @rbs (Prism::Node) -> Prism::Node?
18
+ def value_node(node)
19
+ case node
20
+ when Prism::ConstantWriteNode
21
+ value_node(node.value)
22
+ when Prism::LocalVariableWriteNode
23
+ value_node(node.value)
24
+ else
25
+ node
26
+ end
27
+ end
28
+ end
19
29
 
20
30
  # @rbs!
31
+ # type t = ClassDecl | ModuleDecl | ConstantDecl | SingletonClassDecl | BlockDecl | DataAssignDecl | StructAssignDecl
32
+ #
21
33
  # interface _WithComments
22
34
  # def comments: () -> AnnotationParser::ParsingResult?
23
35
  # end
24
36
 
25
37
  # @rbs module-self _WithComments
26
38
  module Generics
27
- # @rbs returns Array[RBS::AST::TypeParam]
39
+ # @rbs return: Array[RBS::AST::TypeParam]
28
40
  def type_params
29
41
  if comments = comments()
30
- comments.annotations.filter_map do |annotation|
42
+ comments.each_annotation.filter_map do |annotation|
31
43
  if annotation.is_a?(Annotations::Generic)
32
44
  annotation.type_param
33
45
  end
@@ -44,26 +56,26 @@ module RBS
44
56
  # @rbs generic NODE < Prism::Node
45
57
  class ModuleOrClass < Base
46
58
  # The node that represents the declaration
47
- attr_reader :node #:: NODE
59
+ attr_reader :node #: NODE
48
60
 
49
61
  # Leading comment
50
- attr_reader :comments #:: AnnotationParser::ParsingResult?
62
+ attr_reader :comments #: AnnotationParser::ParsingResult?
51
63
 
52
64
  # Members included in the declaration
53
- attr_reader :members #:: Array[Members::t | t]
65
+ attr_reader :members #: Array[Members::t | t]
54
66
 
55
67
  # @rbs node: NODE
56
68
  # @rbs comments: AnnotationParser::ParsingResult?
57
- def initialize(node, comments) #:: void
69
+ def initialize(node, comments) #: void
58
70
  @node = node
59
71
  @comments = comments
60
72
  @members = []
61
73
  end
62
74
 
63
75
  # Type parameters for the declaration
64
- def type_params #:: Array[RBS::AST::TypeParam]
76
+ def type_params #: Array[RBS::AST::TypeParam]
65
77
  if comments = comments()
66
- comments.annotations.filter_map do |annotation|
78
+ comments.each_annotation.filter_map do |annotation|
67
79
  if annotation.is_a?(Annotations::Generic)
68
80
  annotation.type_param
69
81
  end
@@ -73,7 +85,7 @@ module RBS
73
85
  end
74
86
  end
75
87
 
76
- def start_line #:: Integer
88
+ def start_line #: Integer
77
89
  node.location.start_line
78
90
  end
79
91
  end
@@ -82,12 +94,12 @@ module RBS
82
94
  include ConstantUtil
83
95
 
84
96
  # Type application for super class
85
- attr_reader :super_app #:: Annotations::Application?
97
+ attr_reader :super_app #: Annotations::Application?
86
98
 
87
99
  # @rbs node: Prism::ClassNode
88
100
  # @rbs comments: AnnotationParser::ParsingResult?
89
101
  # @rbs super_app: Annotations::Application?
90
- # @rbs returns void
102
+ # @rbs return: void
91
103
  def initialize(node, comments, super_app)
92
104
  super(node, comments)
93
105
 
@@ -95,14 +107,14 @@ module RBS
95
107
  end
96
108
 
97
109
  # @rbs %a{pure}
98
- def class_name #:: TypeName?
110
+ def class_name #: TypeName?
99
111
  type_name(node.constant_path)
100
112
  end
101
113
 
102
114
  # @rbs %a{pure}
103
- def super_class #:: RBS::AST::Declarations::Class::Super?
115
+ def super_class #: RBS::AST::Declarations::Class::Super?
104
116
  if comments
105
- if inherits = comments.annotations.find {|a| a.is_a?(Annotations::Inherits) } #: Annotations::Inherits?
117
+ if inherits = comments.each_annotation.find {|a| a.is_a?(Annotations::Inherits) } #: Annotations::Inherits?
106
118
  super_name = inherits.super_name
107
119
  super_args = inherits.args
108
120
 
@@ -141,14 +153,14 @@ module RBS
141
153
  include ConstantUtil
142
154
 
143
155
  # @rbs %a{pure}
144
- def module_name #:: TypeName?
156
+ def module_name #: TypeName?
145
157
  type_name(node.constant_path)
146
158
  end
147
159
 
148
160
  # @rbs %a{pure}
149
- def module_selfs #:: Array[Annotations::ModuleSelf]
161
+ def module_selfs #: Array[Annotations::ModuleSelf]
150
162
  if comments
151
- comments.annotations.filter_map do |ann|
163
+ comments.each_annotation.filter_map do |ann|
152
164
  if ann.is_a?(AST::Annotations::ModuleSelf)
153
165
  ann
154
166
  end
@@ -162,21 +174,21 @@ module RBS
162
174
  class ConstantDecl < Base
163
175
  include ConstantUtil
164
176
 
165
- attr_reader :node #:: Prism::ConstantWriteNode
166
- attr_reader :comments #:: AnnotationParser::ParsingResult?
167
- attr_reader :assertion #:: Annotations::Assertion?
177
+ attr_reader :node #: Prism::ConstantWriteNode
178
+ attr_reader :comments #: AnnotationParser::ParsingResult?
179
+ attr_reader :assertion #: Annotations::TypeAssertion?
168
180
 
169
181
  # @rbs node: Prism::ConstantWriteNode
170
182
  # @rbs comments: AnnotationParser::ParsingResult?
171
- # @rbs assertion: Annotations::Assertion?
172
- def initialize(node, comments, assertion)
183
+ # @rbs assertion: Annotations::TypeAssertion?
184
+ def initialize(node, comments, assertion) #: void
173
185
  @node = node
174
186
  @comments = comments
175
187
  @assertion = assertion
176
188
  end
177
189
 
178
190
  # @rbs %a{pure}
179
- # @rbs returns Types::t
191
+ # @rbs return: Types::t
180
192
  def type
181
193
  if assertion
182
194
  case assertion.type
@@ -218,18 +230,279 @@ module RBS
218
230
  end
219
231
 
220
232
  # @rbs %a{pure}
221
- # @rbs returns TypeName?
233
+ # @rbs return: TypeName?
222
234
  def constant_name
223
235
  TypeName.new(name: node.name, namespace: Namespace.empty)
224
236
  end
225
237
 
226
- def start_line #:: Integer
238
+ def start_line #: Integer
227
239
  node.location.start_line
228
240
  end
229
241
  end
230
242
 
231
243
  class SingletonClassDecl < ModuleOrClass #[Prism::SingletonClassNode]
232
244
  end
245
+
246
+ class BlockDecl < Base
247
+ attr_reader :node #: Prism::BlockNode
248
+
249
+ attr_reader :comments #: AnnotationParser::ParsingResult?
250
+
251
+ # Members included in the declaration
252
+ attr_reader :members #: Array[Members::t | t]
253
+
254
+ # @rbs (Prism::BlockNode, AnnotationParser::ParsingResult?) -> void
255
+ def initialize(node, comments)
256
+ @node = node
257
+ @members = []
258
+ @comments = comments
259
+ end
260
+
261
+ def start_line #: Integer
262
+ node.location.start_line
263
+ end
264
+
265
+ def module_class_annotation #: Annotations::ModuleDecl | Annotations::ClassDecl | nil
266
+ if comments
267
+ comments.each_annotation.each do |annotation|
268
+ if annotation.is_a?(Annotations::ModuleDecl)
269
+ return annotation
270
+ end
271
+
272
+ if annotation.is_a?(Annotations::ClassDecl)
273
+ return annotation
274
+ end
275
+ end
276
+
277
+ nil
278
+ end
279
+ end
280
+ end
281
+
282
+ # @rbs module-self _WithTypeDecls
283
+ module DataStructUtil
284
+ # @rbs!
285
+ # interface _WithTypeDecls
286
+ # def type_decls: () -> Hash[Integer, Annotations::TypeAssertion]
287
+ #
288
+ # def each_attribute_argument: () { (Prism::Node) -> void } -> void
289
+ #
290
+ # def comments: %a{pure} () -> AnnotationParser::ParsingResult?
291
+ # end
292
+
293
+ # @rbs %a{pure}
294
+ # @rbs () { ([Symbol, Annotations::TypeAssertion?]) -> void } -> void
295
+ # | () -> Enumerator[[Symbol, Annotations::TypeAssertion?], void]
296
+ def each_attribute(&block)
297
+ if block
298
+ each_attribute_argument do |arg|
299
+ if arg.is_a?(Prism::SymbolNode)
300
+ if name = arg.value
301
+ type = type_decls.fetch(arg.location.start_line, nil)
302
+ yield [name.to_sym, type]
303
+ end
304
+ end
305
+ end
306
+ else
307
+ enum_for :each_attribute
308
+ end
309
+ end
310
+
311
+ def class_annotations #: Array[RBS::AST::Annotation]
312
+ annotations = [] #: Array[RBS::AST::Annotation]
313
+
314
+ comments&.each_annotation do |annotation|
315
+ if annotation.is_a?(Annotations::RBSAnnotation)
316
+ annotations.concat annotation.annotations
317
+ end
318
+ end
319
+
320
+ annotations
321
+ end
322
+ end
323
+
324
+ class DataAssignDecl < Base
325
+ extend ConstantUtil
326
+
327
+ include DataStructUtil
328
+
329
+ attr_reader :node #: Prism::ConstantWriteNode
330
+
331
+ attr_reader :comments #: AnnotationParser::ParsingResult?
332
+
333
+ attr_reader :type_decls #: Hash[Integer, Annotations::TypeAssertion]
334
+
335
+ attr_reader :data_define_node #: Prism::CallNode
336
+
337
+ # @rbs (Prism::ConstantWriteNode, Prism::CallNode, AnnotationParser::ParsingResult?, Hash[Integer, Annotations::TypeAssertion]) -> void
338
+ def initialize(node, data_define_node, comments, type_decls)
339
+ @node = node
340
+ @comments = comments
341
+ @type_decls = type_decls
342
+ @data_define_node = data_define_node
343
+ end
344
+
345
+ def start_line #: Integer
346
+ node.location.start_line
347
+ end
348
+
349
+ # @rbs %a{pure}
350
+ # @rbs () -> TypeName?
351
+ def constant_name
352
+ TypeName.new(name: node.name, namespace: Namespace.empty)
353
+ end
354
+
355
+ # @rbs (Prism::ConstantWriteNode) -> Prism::CallNode?
356
+ def self.data_define?(node)
357
+ value = value_node(node)
358
+
359
+ if value.is_a?(Prism::CallNode)
360
+ if value.receiver.is_a?(Prism::ConstantReadNode)
361
+ if value.receiver.full_name.delete_prefix("::") == "Data"
362
+ if value.name == :define
363
+ return value
364
+ end
365
+ end
366
+ end
367
+ end
368
+ end
369
+
370
+ # @rbs () { (Prism::Node) -> void } -> void
371
+ def each_attribute_argument(&block)
372
+ if args = data_define_node.arguments
373
+ args.arguments.each(&block)
374
+ end
375
+ end
376
+ end
377
+
378
+ class StructAssignDecl < Base
379
+ extend ConstantUtil
380
+
381
+ include DataStructUtil
382
+
383
+ attr_reader :node #: Prism::ConstantWriteNode
384
+
385
+ attr_reader :comments #: AnnotationParser::ParsingResult?
386
+
387
+ attr_reader :type_decls #: Hash[Integer, Annotations::TypeAssertion]
388
+
389
+ attr_reader :struct_new_node #: Prism::CallNode
390
+
391
+ # @rbs (Prism::ConstantWriteNode, Prism::CallNode, AnnotationParser::ParsingResult?, Hash[Integer, Annotations::TypeAssertion]) -> void
392
+ def initialize(node, struct_new_node, comments, type_decls)
393
+ @node = node
394
+ @comments = comments
395
+ @type_decls = type_decls
396
+ @struct_new_node = struct_new_node
397
+ end
398
+
399
+ def start_line #: Integer
400
+ node.location.start_line
401
+ end
402
+
403
+ # @rbs %a{pure}
404
+ # @rbs () -> TypeName?
405
+ def constant_name
406
+ TypeName.new(name: node.name, namespace: Namespace.empty)
407
+ end
408
+
409
+ # @rbs () { (Prism::Node) -> void } -> void
410
+ def each_attribute_argument(&block)
411
+ if args = struct_new_node.arguments
412
+ args.arguments.each do |arg|
413
+ next if arg.is_a?(Prism::KeywordHashNode)
414
+ next if arg.is_a?(Prism::StringNode)
415
+
416
+ yield arg
417
+ end
418
+ end
419
+ end
420
+
421
+ # @rbs (Prism::ConstantWriteNode) -> Prism::CallNode?
422
+ def self.struct_new?(node)
423
+ value = value_node(node)
424
+
425
+ if value.is_a?(Prism::CallNode)
426
+ if value.receiver.is_a?(Prism::ConstantReadNode)
427
+ if value.receiver.full_name.delete_prefix("::") == "Struct"
428
+ if value.name == :new
429
+ return value
430
+ end
431
+ end
432
+ end
433
+ end
434
+ end
435
+
436
+ # @rbs %a{pure}
437
+ def keyword_init? #: bool
438
+ if args = struct_new_node.arguments
439
+ args.arguments.each do |arg|
440
+ if arg.is_a?(Prism::KeywordHashNode)
441
+ arg.elements.each do |assoc|
442
+ if assoc.is_a?(Prism::AssocNode)
443
+ if (key = assoc.key).is_a?(Prism::SymbolNode)
444
+ if key.value == "keyword_init"
445
+ value = assoc.value
446
+ if value.is_a?(Prism::FalseNode)
447
+ return false
448
+ end
449
+ end
450
+ end
451
+ end
452
+ end
453
+ end
454
+ end
455
+ end
456
+
457
+ true
458
+ end
459
+
460
+ # @rbs %a{pure}
461
+ def positional_init? #: bool
462
+ if args = struct_new_node.arguments
463
+ args.arguments.each do |arg|
464
+ if arg.is_a?(Prism::KeywordHashNode)
465
+ arg.elements.each do |assoc|
466
+ if assoc.is_a?(Prism::AssocNode)
467
+ if (key = assoc.key).is_a?(Prism::SymbolNode)
468
+ if key.value == "keyword_init"
469
+ value = assoc.value
470
+ if value.is_a?(Prism::TrueNode)
471
+ return false
472
+ end
473
+ end
474
+ end
475
+ end
476
+ end
477
+ end
478
+ end
479
+ end
480
+
481
+ true
482
+ end
483
+
484
+ # Returns `true` is annotation is given to make all attributes *readonly*
485
+ #
486
+ # Add `# @rbs %a{rbs-inline:readonly-attributes=true}` to the class to make all attributes `attr_reader`, instead of `attr_accessor`.
487
+ #
488
+ # @rbs %a{pure}
489
+ def readonly_attributes? #: bool
490
+ class_annotations.any? do |annotation|
491
+ annotation.string == "rbs-inline:readonly-attributes=true"
492
+ end
493
+ end
494
+
495
+ # Returns `true` if annotation is given to make all `.new` arguments required
496
+ #
497
+ # Add `# @rbs %a{rbs-inline:new-args=required}` to the class to make all of the parameters required.
498
+ #
499
+ # @rbs %a{pure}
500
+ def required_new_args? #: bool
501
+ class_annotations.any? do |annotation|
502
+ annotation.string == "rbs-inline:new-args=required"
503
+ end
504
+ end
505
+ end
233
506
  end
234
507
  end
235
508
  end