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.
@@ -17,22 +17,22 @@ module RBS
17
17
  #
18
18
  #
19
19
  class PathCalculator
20
- attr_reader :pwd #:: Pathname
20
+ attr_reader :pwd #: Pathname
21
21
 
22
- attr_reader :base_paths #:: Array[Pathname]
22
+ attr_reader :base_paths #: Array[Pathname]
23
23
 
24
- attr_reader :output_path #:: Pathname
24
+ attr_reader :output_path #: Pathname
25
25
 
26
26
  # @rbs pwd: Pathname
27
27
  # @rbs base_paths: Array[Pathname]
28
28
  # @rbs output_path: Pathname
29
- def initialize(pwd, base_paths, output_path) #:: void
29
+ def initialize(pwd, base_paths, output_path) #: void
30
30
  @pwd = pwd
31
31
  @base_paths = base_paths
32
32
  @output_path = output_path
33
33
  end
34
34
 
35
- #:: (Pathname) -> Pathname?
35
+ #: (Pathname) -> Pathname?
36
36
  def calculate(path)
37
37
  path = pwd + path if path.relative?
38
38
  path = path.cleanpath
@@ -49,18 +49,18 @@ module RBS
49
49
 
50
50
  # @rbs path: Pathname
51
51
  # @rbs prefix: Pathname
52
- # @rbs returns bool
52
+ # @rbs return: bool
53
53
  def has_prefix?(path, prefix:)
54
54
  path.descend.include?(prefix)
55
55
  end
56
56
  end
57
57
 
58
- attr_reader :stdout, :stderr #:: IO
59
- attr_reader :logger #:: Logger
58
+ attr_reader :stdout, :stderr #: IO
59
+ attr_reader :logger #: Logger
60
60
 
61
61
  # @rbs stdout: IO
62
62
  # @rbs stderr: IO
63
- def initialize(stdout: STDOUT, stderr: STDERR) #:: void
63
+ def initialize(stdout: STDOUT, stderr: STDERR) #: void
64
64
  @stdout = stdout
65
65
  @stderr = stderr
66
66
  @logger = Logger.new(stderr)
@@ -68,7 +68,7 @@ module RBS
68
68
  end
69
69
 
70
70
  # @rbs args: Array[String]
71
- # @rbs returns Integer
71
+ # @rbs return: Integer
72
72
  def run(args)
73
73
  base_paths = [Pathname("lib"), Pathname("app")]
74
74
  output_path = nil #: Pathname?
@@ -139,10 +139,10 @@ module RBS
139
139
 
140
140
  logger.debug { "Parsing ruby file #{target}..." }
141
141
 
142
- if (uses, decls = Parser.parse(Prism.parse_file(target.to_s), opt_in: opt_in))
142
+ if (uses, decls, rbs_decls = Parser.parse(Prism.parse_file(target.to_s), opt_in: opt_in))
143
143
  writer = Writer.new()
144
144
  writer.header("Generated from #{target.relative? ? target : target.relative_path_from(Pathname.pwd)} with RBS::Inline")
145
- writer.write(uses, decls)
145
+ writer.write(uses, decls, rbs_decls)
146
146
 
147
147
  if output
148
148
  unless output.parent.directory?
@@ -4,7 +4,7 @@ module RBS
4
4
  module Inline
5
5
  module NodeUtils
6
6
  # @rbs node: Prism::Node
7
- # @rbs returns TypeName?
7
+ # @rbs return: TypeName?
8
8
  def type_name(node)
9
9
  case node
10
10
  when Prism::ConstantReadNode
@@ -5,13 +5,18 @@
5
5
  module RBS
6
6
  module Inline
7
7
  class Parser < Prism::Visitor
8
+ # @rbs! type with_members = AST::Declarations::ModuleDecl
9
+ # | AST::Declarations::ClassDecl
10
+ # | AST::Declarations::SingletonClassDecl
11
+ # | AST::Declarations::BlockDecl
12
+
8
13
  # The top level declarations
9
14
  #
10
- attr_reader :decls #:: Array[AST::Declarations::t]
15
+ attr_reader :decls #: Array[AST::Declarations::t]
11
16
 
12
17
  # The surrounding declarations
13
18
  #
14
- attr_reader :surrounding_decls #:: Array[AST::Declarations::ModuleDecl | AST::Declarations::ClassDecl]
19
+ attr_reader :surrounding_decls #: Array[with_members]
15
20
 
16
21
  # ParsingResult associated with the line number at the end
17
22
  #
@@ -23,24 +28,35 @@ module RBS
23
28
  # > [!IMPORTANT]
24
29
  # > The values will be removed during parsing.
25
30
  #
26
- attr_reader :comments #:: Hash[Integer, AnnotationParser::ParsingResult]
31
+ attr_reader :comments #: Hash[Integer, AnnotationParser::ParsingResult]
27
32
 
28
33
  # The current visibility applied to single `def` node
29
34
  #
30
35
  # Assuming it's directly inside `private` or `public` calls.
31
36
  # `nil` when the `def` node is not inside `private` or `public` calls.
32
37
  #
33
- attr_reader :current_visibility #:: RBS::AST::Members::visibility?
38
+ attr_reader :current_visibility #: RBS::AST::Members::visibility?
34
39
 
35
- def initialize() #:: void
40
+ def initialize() #: void
36
41
  @decls = []
37
42
  @surrounding_decls = []
38
43
  @comments = {}
39
44
  end
40
45
 
46
+ # Parses the given Prism result to a three tuple
47
+ #
48
+ # Returns a three tuple of:
49
+ #
50
+ # 1. An array of `use` directives
51
+ # 2. An array of declarations
52
+ # 3. An array of RBS declarations given as `@rbs!` annotation at top-level
53
+ #
54
+ # Note that only RBS declarations are allowed in the top-level `@rbs!` annotations.
55
+ # RBS *members* are ignored in the array.
56
+ #
41
57
  # @rbs result: ParseResult
42
58
  # @rbs opt_in: bool -- `true` for *opt-out* mode, `false` for *opt-in* mode.
43
- # @rbs returns [Array[AST::Annotations::Use], Array[AST::Declarations::t]]?
59
+ # @rbs return: [Array[AST::Annotations::Use], Array[AST::Declarations::t], Array[RBS::AST::Declarations::t]]?
44
60
  def self.parse(result, opt_in:)
45
61
  instance = Parser.new()
46
62
 
@@ -61,7 +77,7 @@ module RBS
61
77
 
62
78
  uses = [] #: Array[AST::Annotations::Use]
63
79
  annots.each do |annot|
64
- annot.annotations.each do |annotation|
80
+ annot.each_annotation do |annotation|
65
81
  if annotation.is_a?(AST::Annotations::Use)
66
82
  uses << annotation
67
83
  end
@@ -70,24 +86,44 @@ module RBS
70
86
 
71
87
  instance.visit(result.value)
72
88
 
89
+ rbs_embeddeds = [] #: Array[AST::Members::RBSEmbedded]
90
+
91
+ instance.comments.each_value do |comment|
92
+ comment.each_annotation do |annotation|
93
+ if annotation.is_a?(AST::Annotations::Embedded)
94
+ rbs_embeddeds << AST::Members::RBSEmbedded.new(comment, annotation)
95
+ end
96
+ end
97
+ end
98
+
99
+ rbs_decls = rbs_embeddeds.flat_map do |embedded|
100
+ if (members = embedded.members).is_a?(Array)
101
+ members.select do |member|
102
+ member.is_a?(RBS::AST::Declarations::Base)
103
+ end
104
+ else
105
+ []
106
+ end #: Array[RBS::AST::Declarations::t]
107
+ end
108
+
73
109
  [
74
110
  uses,
75
- instance.decls
111
+ instance.decls,
112
+ rbs_decls
76
113
  ]
77
114
  end
78
115
 
79
- # @rbs returns AST::Declarations::ModuleDecl | AST::Declarations::ClassDecl | nil
116
+ # @rbs return: with_members?
80
117
  def current_class_module_decl
81
118
  surrounding_decls.last
82
119
  end
83
120
 
84
- # @rbs returns AST::Declarations::ModuleDecl | AST::Declarations::ClassDecl
121
+ # @rbs return: with_members
85
122
  def current_class_module_decl!
86
123
  current_class_module_decl or raise
87
124
  end
88
125
 
89
- #:: (AST::Declarations::ModuleDecl | AST::Declarations::ClassDecl | AST::Declarations::SingletonClassDecl) { () -> void } -> void
90
- #:: (AST::Declarations::ConstantDecl) -> void
126
+ #: (with_members) { () -> void } -> void
91
127
  def push_class_module_decl(decl)
92
128
  if current = current_class_module_decl
93
129
  current.members << decl
@@ -96,7 +132,7 @@ module RBS
96
132
  end
97
133
 
98
134
  if block_given?
99
- surrounding_decls.push(_ = decl)
135
+ surrounding_decls.push(decl)
100
136
  begin
101
137
  yield
102
138
  ensure
@@ -114,11 +150,11 @@ module RBS
114
150
  # @rbs members: Array[AST::Members::t | AST::Declarations::t] --
115
151
  # The destination.
116
152
  # The method doesn't insert declarations, but have it to please type checker.
117
- def load_inner_annotations(start_line, end_line, members) #:: void
153
+ def load_inner_annotations(start_line, end_line, members) #: void
118
154
  comments = inner_annotations(start_line, end_line)
119
155
 
120
156
  comments.each do |comment|
121
- comment.annotations.each do |annotation|
157
+ comment.each_annotation do |annotation|
122
158
  case annotation
123
159
  when AST::Annotations::IvarType
124
160
  members << AST::Members::RBSIvar.new(comment, annotation)
@@ -133,51 +169,53 @@ module RBS
133
169
 
134
170
  # @rbs override
135
171
  def visit_class_node(node)
136
- return if ignored_node?(node)
172
+ process_nesting_node(node) do
173
+ visit node.constant_path
174
+ visit node.superclass
137
175
 
138
- visit node.constant_path
139
- visit node.superclass
176
+ associated_comment = comments.delete(node.location.start_line - 1)
177
+ if node.superclass
178
+ app_comment = application_annotation(node.superclass)
179
+ end
140
180
 
141
- associated_comment = comments.delete(node.location.start_line - 1)
142
- if node.superclass
143
- app_comment = application_annotation(node.superclass)
144
- end
181
+ class_decl = AST::Declarations::ClassDecl.new(node, associated_comment, app_comment)
145
182
 
146
- class_decl = AST::Declarations::ClassDecl.new(node, associated_comment, app_comment)
183
+ push_class_module_decl(class_decl) do
184
+ visit node.body
185
+ end
147
186
 
148
- push_class_module_decl(class_decl) do
149
- visit node.body
187
+ load_inner_annotations(node.location.start_line, node.location.end_line, class_decl.members)
150
188
  end
151
-
152
- load_inner_annotations(node.location.start_line, node.location.end_line, class_decl.members)
153
189
  end
154
190
 
155
191
  # @rbs override
156
192
  def visit_singleton_class_node(node)
157
- return if ignored_node?(node)
193
+ process_nesting_node(node) do
194
+ associated_comment = comments.delete(node.location.start_line - 1)
195
+ singleton_decl = AST::Declarations::SingletonClassDecl.new(node, associated_comment)
158
196
 
159
- associated_comment = comments.delete(node.location.start_line - 1)
160
- singleton_decl = AST::Declarations::SingletonClassDecl.new(node, associated_comment)
197
+ push_class_module_decl(singleton_decl) do
198
+ visit node.body
199
+ end
161
200
 
162
- push_class_module_decl(singleton_decl) do
163
- visit node.body
201
+ load_inner_annotations(node.location.start_line, node.location.end_line, singleton_decl.members)
164
202
  end
165
203
  end
166
204
 
167
205
  # @rbs override
168
206
  def visit_module_node(node)
169
- return if ignored_node?(node)
207
+ process_nesting_node(node) do
208
+ visit node.constant_path
170
209
 
171
- visit node.constant_path
210
+ associated_comment = comments.delete(node.location.start_line - 1)
172
211
 
173
- associated_comment = comments.delete(node.location.start_line - 1)
212
+ module_decl = AST::Declarations::ModuleDecl.new(node, associated_comment)
213
+ push_class_module_decl(module_decl) do
214
+ visit node.body
215
+ end
174
216
 
175
- module_decl = AST::Declarations::ModuleDecl.new(node, associated_comment)
176
- push_class_module_decl(module_decl) do
177
- visit node.body
217
+ load_inner_annotations(node.location.start_line, node.location.end_line, module_decl.members)
178
218
  end
179
-
180
- load_inner_annotations(node.location.start_line, node.location.end_line, module_decl.members)
181
219
  end
182
220
 
183
221
  # Returns an array of annotations from comments that is located between start_line and end_line
@@ -191,7 +229,7 @@ module RBS
191
229
  #
192
230
  # @rbs start_line: Integer
193
231
  # @rbs end_line: Integer
194
- def inner_annotations(start_line, end_line) #:: Array[AnnotationParser::ParsingResult]
232
+ def inner_annotations(start_line, end_line) #: Array[AnnotationParser::ParsingResult]
195
233
  annotations = comments.each_value.select do |annotation|
196
234
  range = annotation.line_range
197
235
  start_line < range.begin && range.end < end_line
@@ -204,25 +242,27 @@ module RBS
204
242
 
205
243
  # @rbs override
206
244
  def visit_def_node(node)
207
- return if ignored_node?(node)
208
- return unless current_class_module_decl
245
+ process_nesting_node(node) do
246
+ return unless current_class_module_decl
209
247
 
210
- current_decl = current_class_module_decl!
248
+ current_decl = current_class_module_decl!
211
249
 
212
- if node.location
213
- associated_comment = comments.delete(node.location.start_line - 1)
214
- end
250
+ if node.location
251
+ associated_comment = comments.delete(node.location.start_line - 1)
252
+ end
215
253
 
216
- assertion = assertion_annotation(node.rparen_loc || node&.parameters&.location || node.name_loc)
254
+ assertion = assertion_annotation(node.rparen_loc || node&.parameters&.location || node.name_loc)
217
255
 
218
- current_decl.members << AST::Members::RubyDef.new(node, associated_comment, current_visibility, assertion)
256
+ current_decl.members << AST::Members::RubyDef.new(node, associated_comment, current_visibility, assertion)
219
257
 
220
- super
258
+ super
259
+ end
221
260
  end
222
261
 
223
262
  # @rbs override
224
263
  def visit_alias_method_node(node)
225
264
  return if ignored_node?(node)
265
+ return unless current_class_module_decl
226
266
 
227
267
  if node.location
228
268
  comment = comments.delete(node.location.start_line - 1)
@@ -256,9 +296,9 @@ module RBS
256
296
  end
257
297
  if assertion_comment && comment_line
258
298
  comments.delete(comment_line)
259
- assertion = assertion_comment.annotations.find do |annotation|
260
- annotation.is_a?(AST::Annotations::Assertion)
261
- end #: AST::Annotations::Assertion?
299
+ assertion = assertion_comment.each_annotation.find do |annotation|
300
+ annotation.is_a?(AST::Annotations::TypeAssertion)
301
+ end #: AST::Annotations::TypeAssertion?
262
302
  end
263
303
 
264
304
  current_class_module_decl!.members << AST::Members::RubyAttr.new(node, comment, assertion)
@@ -296,8 +336,8 @@ module RBS
296
336
  end
297
337
 
298
338
  # @rbs new_visibility: RBS::AST::Members::visibility?
299
- # @rbs block: ^() -> void
300
- # @rbs returns void
339
+ # @rbs &block: () -> void
340
+ # @rbs return: void
301
341
  def push_visibility(new_visibility, &block)
302
342
  old_visibility = current_visibility
303
343
 
@@ -309,11 +349,21 @@ module RBS
309
349
  end
310
350
  end
311
351
 
352
+ # @rbs [A] (Node) { () -> A } -> A?
353
+ def process_nesting_node(node)
354
+ yield unless ignored_node?(node)
355
+ ensure
356
+ # Delete all inner annotations
357
+ inner_annotations(node.location.start_line, node.location.end_line)
358
+ comments.delete(node.location.start_line)
359
+ comments.delete(node.location.end_line)
360
+ end
361
+
312
362
  # @rbs node: Node
313
- # @rbs returns bool
363
+ # @rbs return: bool
314
364
  def ignored_node?(node)
315
365
  if comment = comments.fetch(node.location.start_line - 1, nil)
316
- comment.annotations.any? { _1.is_a?(AST::Annotations::Skip) }
366
+ comment.each_annotation.any? { _1.is_a?(AST::Annotations::Skip) }
317
367
  else
318
368
  false
319
369
  end
@@ -324,7 +374,7 @@ module RBS
324
374
  # The application annotation is removed from `comments`.
325
375
  #
326
376
  # @rbs node: Node
327
- # @rbs returns AST::Annotations::Application?
377
+ # @rbs return: AST::Annotations::Application?
328
378
  def application_annotation(node)
329
379
  comment_line, app_comment = comments.find do |_, comment|
330
380
  comment.line_range.begin == node.location.end_line
@@ -332,18 +382,18 @@ module RBS
332
382
 
333
383
  if app_comment && comment_line
334
384
  comments.delete(comment_line)
335
- app_comment.annotations.find do |annotation|
385
+ app_comment.each_annotation.find do |annotation|
336
386
  annotation.is_a?(AST::Annotations::Application)
337
387
  end #: AST::Annotations::Application?
338
388
  end
339
389
  end
340
390
 
341
- # Fetch Assertion annotation which is associated to `node`
391
+ # Fetch TypeAssertion annotation which is associated to `node`
342
392
  #
343
393
  # The assertion annotation is removed from `comments`.
344
394
  #
345
395
  # @rbs node: Node | Location
346
- # @rbs returns AST::Annotations::Assertion?
396
+ # @rbs return: AST::Annotations::TypeAssertion?
347
397
  def assertion_annotation(node)
348
398
  if node.is_a?(Prism::Location)
349
399
  location = node
@@ -356,9 +406,9 @@ module RBS
356
406
 
357
407
  if app_comment && comment_line
358
408
  comments.delete(comment_line)
359
- app_comment.annotations.find do |annotation|
360
- annotation.is_a?(AST::Annotations::Assertion)
361
- end #: AST::Annotations::Assertion?
409
+ app_comment.each_annotation.find do |annotation|
410
+ annotation.is_a?(AST::Annotations::TypeAssertion)
411
+ end #: AST::Annotations::TypeAssertion?
362
412
  end
363
413
  end
364
414
 
@@ -367,10 +417,58 @@ module RBS
367
417
  return if ignored_node?(node)
368
418
 
369
419
  comment = comments.delete(node.location.start_line - 1)
370
- assertion = assertion_annotation(node)
371
420
 
372
- decl = AST::Declarations::ConstantDecl.new(node, comment, assertion)
373
- push_class_module_decl(decl)
421
+ case
422
+ when data_node = AST::Declarations::DataAssignDecl.data_define?(node)
423
+ type_decls = {} #: Hash[Integer, AST::Annotations::TypeAssertion]
424
+
425
+ inner_annotations(node.location.start_line, node.location.end_line).flat_map do |comment|
426
+ comment.each_annotation do |annotation|
427
+ if annotation.is_a?(AST::Annotations::TypeAssertion)
428
+ start_line = annotation.source.comments[0].location.start_line
429
+ type_decls[start_line] = annotation
430
+ end
431
+ end
432
+ end
433
+
434
+ decl = AST::Declarations::DataAssignDecl.new(node, data_node, comment, type_decls)
435
+ when struct_node = AST::Declarations::StructAssignDecl.struct_new?(node)
436
+ type_decls = {} #: Hash[Integer, AST::Annotations::TypeAssertion]
437
+
438
+ inner_annotations(node.location.start_line, node.location.end_line).flat_map do |comment|
439
+ comment.each_annotation do |annotation|
440
+ if annotation.is_a?(AST::Annotations::TypeAssertion)
441
+ start_line = annotation.source.comments[0].location.start_line
442
+ type_decls[start_line] = annotation
443
+ end
444
+ end
445
+ end
446
+
447
+ decl = AST::Declarations::StructAssignDecl.new(node, struct_node, comment, type_decls)
448
+ else
449
+ assertion = assertion_annotation(node)
450
+ decl = AST::Declarations::ConstantDecl.new(node, comment, assertion)
451
+ end
452
+
453
+ if current = current_class_module_decl
454
+ current.members << decl
455
+ else
456
+ decls << decl
457
+ end
458
+ end
459
+
460
+ # @rbs override
461
+ def visit_block_node(node)
462
+ process_nesting_node(node) do
463
+ comment = comments.delete(node.location.start_line - 1)
464
+ block = AST::Declarations::BlockDecl.new(node, comment)
465
+
466
+ push_class_module_decl(block) do
467
+ super
468
+ end
469
+
470
+ load_inner_annotations(node.location.start_line, node.location.end_line, block.members)
471
+ end
374
472
  end
375
473
  end
376
474
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RBS
4
4
  module Inline
5
- VERSION = "0.4.0"
5
+ VERSION = "0.6.0"
6
6
  end
7
7
  end