rbs-inline 0.1.0
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 +7 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +109 -0
- data/Rakefile +12 -0
- data/Steepfile +27 -0
- data/exe/rbs-inline +6 -0
- data/lib/rbs/inline/annotation_parser.rb +765 -0
- data/lib/rbs/inline/ast/annotations.rb +454 -0
- data/lib/rbs/inline/ast/comment_lines.rb +42 -0
- data/lib/rbs/inline/ast/declarations.rb +243 -0
- data/lib/rbs/inline/ast/members.rb +599 -0
- data/lib/rbs/inline/ast/tree.rb +141 -0
- data/lib/rbs/inline/cli.rb +106 -0
- data/lib/rbs/inline/node_utils.rb +12 -0
- data/lib/rbs/inline/parser.rb +360 -0
- data/lib/rbs/inline/version.rb +7 -0
- data/lib/rbs/inline/writer.rb +210 -0
- data/lib/rbs/inline.rb +22 -0
- data/rbs_collection.lock.yaml +68 -0
- data/rbs_collection.yaml +17 -0
- data/sig/generated/rbs/inline/annotation_parser.rbs +222 -0
- data/sig/generated/rbs/inline/ast/annotations.rbs +185 -0
- data/sig/generated/rbs/inline/ast/declarations.rbs +116 -0
- data/sig/generated/rbs/inline/ast/members.rbs +179 -0
- data/sig/generated/rbs/inline/cli.rbs +21 -0
- data/sig/generated/rbs/inline/parser.rbs +116 -0
- data/sig/rbs/inline/annotation_parser.rbs +0 -0
- data/sig/rbs/inline/ast/comment_lines.rbs +27 -0
- data/sig/rbs/inline/ast/members.rbs +24 -0
- data/sig/rbs/inline/ast/tree.rbs +98 -0
- data/sig/rbs/inline/node_utils.rbs +7 -0
- data/sig/rbs/inline/writer.rbs +27 -0
- data/sig/rbs/inline.rbs +41 -0
- data/yard-samples/hello.rb +6 -0
- data/yard-samples/sample1.rb +26 -0
- metadata +111 -0
@@ -0,0 +1,141 @@
|
|
1
|
+
module RBS
|
2
|
+
module Inline
|
3
|
+
module AST
|
4
|
+
class Tree
|
5
|
+
attr_reader :trees
|
6
|
+
attr_reader :type
|
7
|
+
attr_reader :non_trivia_trees
|
8
|
+
|
9
|
+
def initialize(type)
|
10
|
+
@type = type
|
11
|
+
@trees = []
|
12
|
+
@non_trivia_trees = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def <<(tok)
|
16
|
+
trees << tok
|
17
|
+
unless tok.is_a?(Array) && tok[0] == :tWHITESPACE
|
18
|
+
non_trivia_trees << tok
|
19
|
+
end
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
buf = +""
|
25
|
+
|
26
|
+
trees.each do |tree|
|
27
|
+
case tree
|
28
|
+
when Array
|
29
|
+
buf << tree[1]
|
30
|
+
when Tree
|
31
|
+
buf << tree.to_s
|
32
|
+
when nil
|
33
|
+
else
|
34
|
+
loc = tree.location or raise
|
35
|
+
buf << loc.source
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
buf
|
40
|
+
end
|
41
|
+
|
42
|
+
def nth_token(index)
|
43
|
+
tok = non_trivia_trees[index]
|
44
|
+
case tok
|
45
|
+
when Array, nil
|
46
|
+
tok
|
47
|
+
else
|
48
|
+
raise
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def nth_token?(index)
|
53
|
+
tok = non_trivia_trees[index]
|
54
|
+
case tok
|
55
|
+
when Array
|
56
|
+
tok
|
57
|
+
else
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def nth_token!(index)
|
63
|
+
nth_token(index) || raise
|
64
|
+
end
|
65
|
+
|
66
|
+
def nth_tree(index)
|
67
|
+
tok = non_trivia_trees[index]
|
68
|
+
case tok
|
69
|
+
when Tree, nil
|
70
|
+
tok
|
71
|
+
else
|
72
|
+
raise
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def nth_tree?(index)
|
77
|
+
tok = non_trivia_trees[index]
|
78
|
+
case tok
|
79
|
+
when Tree
|
80
|
+
tok
|
81
|
+
else
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def nth_tree!(index)
|
87
|
+
nth_tree(index) || raise
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
def nth_type(index)
|
92
|
+
tok = non_trivia_trees[index]
|
93
|
+
case tok
|
94
|
+
when Array, Tree, MethodType
|
95
|
+
raise
|
96
|
+
else
|
97
|
+
tok
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def nth_type?(index)
|
102
|
+
tok = non_trivia_trees[index]
|
103
|
+
case tok
|
104
|
+
when Array, Tree, nil, MethodType
|
105
|
+
nil
|
106
|
+
else
|
107
|
+
tok
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def nth_type!(index)
|
112
|
+
nth_type(index) || raise
|
113
|
+
end
|
114
|
+
|
115
|
+
def nth_method_type(index)
|
116
|
+
tok = non_trivia_trees[index]
|
117
|
+
case tok
|
118
|
+
when MethodType, nil
|
119
|
+
tok
|
120
|
+
else
|
121
|
+
raise
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def nth_method_type?(index)
|
126
|
+
tok = non_trivia_trees[index]
|
127
|
+
case tok
|
128
|
+
when MethodType
|
129
|
+
tok
|
130
|
+
else
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def nth_method_type!(index)
|
136
|
+
nth_method_type(index) || raise
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
|
3
|
+
require "optparse"
|
4
|
+
|
5
|
+
module RBS
|
6
|
+
module Inline
|
7
|
+
class CLI
|
8
|
+
attr_reader :stdout, :stderr #:: IO
|
9
|
+
attr_reader :logger #:: Logger
|
10
|
+
|
11
|
+
# @rbs stdout: IO
|
12
|
+
# @rbs stderr: IO
|
13
|
+
def initialize(stdout: STDOUT, stderr: STDERR) #:: void
|
14
|
+
@stdout = stdout
|
15
|
+
@stderr = stderr
|
16
|
+
@logger = Logger.new(stderr)
|
17
|
+
logger.level = :ERROR
|
18
|
+
end
|
19
|
+
|
20
|
+
# @rbs args: Array[String]
|
21
|
+
# @rbs returns Integer
|
22
|
+
def run(args)
|
23
|
+
base_path = Pathname("lib")
|
24
|
+
output_path = nil #: Pathname?
|
25
|
+
|
26
|
+
OptionParser.new do |opts|
|
27
|
+
opts.on("--base=[BASE]", "The path to calculate relative path of files (defaults to #{base_path})") do
|
28
|
+
base_path = Pathname(_1)
|
29
|
+
end
|
30
|
+
|
31
|
+
opts.on("--output=[BASE]", "The directory where the RBS files are saved at (defaults to STDOUT if not specified)") do
|
32
|
+
output_path = Pathname(_1)
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("--verbose") do
|
36
|
+
logger.level = :DEBUG
|
37
|
+
end
|
38
|
+
end.parse!(args)
|
39
|
+
|
40
|
+
base_path = Pathname.pwd + base_path
|
41
|
+
|
42
|
+
logger.debug { "base_path = #{base_path}, output_path = #{output_path}" }
|
43
|
+
|
44
|
+
targets = args.flat_map do
|
45
|
+
path = Pathname(_1)
|
46
|
+
|
47
|
+
if path.directory?
|
48
|
+
pattern = path + "**/*.rb"
|
49
|
+
Pathname.glob(pattern.to_s)
|
50
|
+
else
|
51
|
+
path
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
targets.sort!
|
56
|
+
targets.uniq!
|
57
|
+
|
58
|
+
count = 0
|
59
|
+
|
60
|
+
targets.each do |target|
|
61
|
+
relative_path = (Pathname.pwd + target).relative_path_from(base_path)
|
62
|
+
if output_path
|
63
|
+
output = output_path + relative_path.sub_ext(".rbs")
|
64
|
+
|
65
|
+
unless output.to_s.start_with?(output_path.to_s)
|
66
|
+
raise "Cannot calculate the output file path for #{target} in #{output_path}"
|
67
|
+
end
|
68
|
+
|
69
|
+
logger.debug { "Generating #{output} from #{target} ..." }
|
70
|
+
else
|
71
|
+
logger.debug { "Generating RBS declaration from #{target} ..." }
|
72
|
+
end
|
73
|
+
|
74
|
+
logger.debug { "Parsing ruby file #{target}..." }
|
75
|
+
|
76
|
+
if (uses, decls = Parser.parse(Prism.parse_file(target.to_s)))
|
77
|
+
writer = Writer.new()
|
78
|
+
writer.header("Generated from #{target.relative? ? target : target.relative_path_from(Pathname.pwd)} with RBS::Inline")
|
79
|
+
writer.write(uses, decls)
|
80
|
+
|
81
|
+
if output
|
82
|
+
unless output.parent.directory?
|
83
|
+
logger.debug { "Making directory #{output.parent}..." }
|
84
|
+
output.parent.mkpath
|
85
|
+
end
|
86
|
+
|
87
|
+
logger.debug { "Writing RBS file to #{output}..." }
|
88
|
+
output.write(writer.output)
|
89
|
+
else
|
90
|
+
stdout.puts writer.output
|
91
|
+
stdout.puts
|
92
|
+
end
|
93
|
+
|
94
|
+
count += 1
|
95
|
+
else
|
96
|
+
logger.debug { "Skipping #{target} because `# rbs_inline: enabled` comment not found" }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
stderr.puts "🎉 Generated #{count} RBS files under #{output_path}"
|
101
|
+
|
102
|
+
0
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,360 @@
|
|
1
|
+
# rbs_inline: enabled
|
2
|
+
|
3
|
+
# @rbs use Prism::*
|
4
|
+
|
5
|
+
module RBS
|
6
|
+
module Inline
|
7
|
+
class Parser < Prism::Visitor
|
8
|
+
# The top level declarations
|
9
|
+
#
|
10
|
+
attr_reader :decls #:: Array[AST::Declarations::t]
|
11
|
+
|
12
|
+
# The surrounding declarations
|
13
|
+
#
|
14
|
+
attr_reader :surrounding_decls #:: Array[AST::Declarations::ModuleDecl | AST::Declarations::ClassDecl]
|
15
|
+
|
16
|
+
# ParsingResult associated with the line number at the end
|
17
|
+
#
|
18
|
+
# ```rb
|
19
|
+
# # Hello
|
20
|
+
# # world <= The comments hash includes `2` (line 2) to the two lines
|
21
|
+
# ```
|
22
|
+
#
|
23
|
+
# > [!IMPORTANT]
|
24
|
+
# > The values will be removed during parsing.
|
25
|
+
#
|
26
|
+
attr_reader :comments #:: Hash[Integer, AnnotationParser::ParsingResult]
|
27
|
+
|
28
|
+
# The current visibility applied to single `def` node
|
29
|
+
#
|
30
|
+
# Assuming it's directly inside `private` or `public` calls.
|
31
|
+
# `nil` when the `def` node is not inside `private` or `public` calls.
|
32
|
+
#
|
33
|
+
attr_reader :current_visibility #:: RBS::AST::Members::visibility?
|
34
|
+
|
35
|
+
def initialize() #:: void
|
36
|
+
@decls = []
|
37
|
+
@surrounding_decls = []
|
38
|
+
@comments = {}
|
39
|
+
end
|
40
|
+
|
41
|
+
# @rbs result: ParseResult[ProgramNode]
|
42
|
+
# @rbs returns [Array[AST::Annotations::Use], Array[AST::Declarations::t]]?
|
43
|
+
def self.parse(result)
|
44
|
+
instance = Parser.new()
|
45
|
+
|
46
|
+
# pp result
|
47
|
+
|
48
|
+
annots = AnnotationParser.parse(result.comments)
|
49
|
+
annots.each do |result|
|
50
|
+
instance.comments[result.line_range.end] = result
|
51
|
+
end
|
52
|
+
|
53
|
+
if result.comments.none? {|comment| comment.location.slice =~ /\A# rbs_inline: enabled\Z/}
|
54
|
+
return
|
55
|
+
end
|
56
|
+
|
57
|
+
uses = [] #: Array[AST::Annotations::Use]
|
58
|
+
annots.each do |annot|
|
59
|
+
annot.annotations.each do |annotation|
|
60
|
+
if annotation.is_a?(AST::Annotations::Use)
|
61
|
+
uses << annotation
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
instance.visit(result.value)
|
67
|
+
|
68
|
+
[
|
69
|
+
uses,
|
70
|
+
instance.decls
|
71
|
+
]
|
72
|
+
end
|
73
|
+
|
74
|
+
# @rbs rturns AST::Declarations::ModuleDecl | AST::Declarations::ClassDecl | nil
|
75
|
+
def current_class_module_decl
|
76
|
+
surrounding_decls.last
|
77
|
+
end
|
78
|
+
|
79
|
+
# @rbs returns AST::Declarations::ModuleDecl | AST::Declarations::ClassDecl
|
80
|
+
def current_class_module_decl!
|
81
|
+
current_class_module_decl or raise
|
82
|
+
end
|
83
|
+
|
84
|
+
#:: (AST::Declarations::ModuleDecl | AST::Declarations::ClassDecl) { () -> void } -> void
|
85
|
+
#:: (AST::Declarations::ConstantDecl) -> void
|
86
|
+
def push_class_module_decl(decl)
|
87
|
+
if current = current_class_module_decl
|
88
|
+
current.members << decl
|
89
|
+
else
|
90
|
+
decls << decl
|
91
|
+
end
|
92
|
+
|
93
|
+
if block_given?
|
94
|
+
surrounding_decls.push(_ = decl)
|
95
|
+
begin
|
96
|
+
yield
|
97
|
+
ensure
|
98
|
+
surrounding_decls.pop()
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Load inner declarations and delete them from `#comments` hash
|
104
|
+
#
|
105
|
+
# It also sorts the `members` by `#start_line`` ascending.
|
106
|
+
#
|
107
|
+
# @rbs start_line: Integer
|
108
|
+
# @rbs end_line: Integer
|
109
|
+
# @rbs members: Array[AST::Members::t | AST::Declarations::t] --
|
110
|
+
# The destination.
|
111
|
+
# The method doesn't insert declarations, but have it to please type checker.
|
112
|
+
def load_inner_annotations(start_line, end_line, members) #:: void
|
113
|
+
comments = inner_annotations(start_line, end_line)
|
114
|
+
|
115
|
+
comments.each do |comment|
|
116
|
+
comment.annotations.each do |annotation|
|
117
|
+
case annotation
|
118
|
+
when AST::Annotations::IvarType
|
119
|
+
members << AST::Members::RBSIvar.new(comment, annotation)
|
120
|
+
when AST::Annotations::Embedded
|
121
|
+
members << AST::Members::RBSEmbedded.new(comment, annotation)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
members.sort_by! { _1.start_line }
|
127
|
+
end
|
128
|
+
|
129
|
+
# @rbs override
|
130
|
+
def visit_class_node(node)
|
131
|
+
return if ignored_node?(node)
|
132
|
+
|
133
|
+
visit node.constant_path
|
134
|
+
visit node.superclass
|
135
|
+
|
136
|
+
associated_comment = comments.delete(node.location.start_line - 1)
|
137
|
+
if node.superclass
|
138
|
+
app_comment = application_annotation(node.superclass)
|
139
|
+
end
|
140
|
+
|
141
|
+
class_decl = AST::Declarations::ClassDecl.new(node, associated_comment, app_comment)
|
142
|
+
|
143
|
+
push_class_module_decl(class_decl) do
|
144
|
+
visit node.body
|
145
|
+
end
|
146
|
+
|
147
|
+
load_inner_annotations(node.location.start_line, node.location.end_line, class_decl.members)
|
148
|
+
end
|
149
|
+
|
150
|
+
# @rbs override
|
151
|
+
def visit_module_node(node)
|
152
|
+
return if ignored_node?(node)
|
153
|
+
|
154
|
+
visit node.constant_path
|
155
|
+
|
156
|
+
associated_comment = comments.delete(node.location.start_line - 1)
|
157
|
+
|
158
|
+
module_decl = AST::Declarations::ModuleDecl.new(node, associated_comment)
|
159
|
+
push_class_module_decl(module_decl) do
|
160
|
+
visit node.body
|
161
|
+
end
|
162
|
+
|
163
|
+
load_inner_annotations(node.location.start_line, node.location.end_line, module_decl.members)
|
164
|
+
end
|
165
|
+
|
166
|
+
# Returns an array of annotations from comments that is located between start_line and end_line
|
167
|
+
#
|
168
|
+
# ```rb
|
169
|
+
# module Foo # line 1 (start_line)
|
170
|
+
# # foo
|
171
|
+
# # bar
|
172
|
+
# end # line 4 (end_line)
|
173
|
+
# ```
|
174
|
+
#
|
175
|
+
# @rbs start_line: Integer
|
176
|
+
# @rbs end_line: Integer
|
177
|
+
def inner_annotations(start_line, end_line) #:: Array[AnnotationParser::ParsingResult]
|
178
|
+
annotations = comments.each_value.select do |annotation|
|
179
|
+
range = annotation.line_range
|
180
|
+
start_line < range.begin && range.end < end_line
|
181
|
+
end
|
182
|
+
|
183
|
+
annotations.each do |annot|
|
184
|
+
comments.delete(annot.line_range.end)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# @rbs override
|
189
|
+
def visit_def_node(node)
|
190
|
+
return if ignored_node?(node)
|
191
|
+
return unless current_class_module_decl
|
192
|
+
|
193
|
+
current_decl = current_class_module_decl!
|
194
|
+
|
195
|
+
if node.location
|
196
|
+
associated_comment = comments.delete(node.location.start_line - 1)
|
197
|
+
end
|
198
|
+
|
199
|
+
assertion = assertion_annotation(node.rparen_loc || node&.parameters&.location || node.name_loc)
|
200
|
+
|
201
|
+
current_decl.members << AST::Members::RubyDef.new(node, associated_comment, current_visibility, assertion)
|
202
|
+
|
203
|
+
super
|
204
|
+
end
|
205
|
+
|
206
|
+
# @rbs override
|
207
|
+
def visit_alias_method_node(node)
|
208
|
+
return if ignored_node?(node)
|
209
|
+
|
210
|
+
if node.location
|
211
|
+
comment = comments.delete(node.location.start_line - 1)
|
212
|
+
end
|
213
|
+
current_class_module_decl!.members << AST::Members::RubyAlias.new(node, comment)
|
214
|
+
super
|
215
|
+
end
|
216
|
+
|
217
|
+
# @rbs override
|
218
|
+
def visit_call_node(node)
|
219
|
+
return if ignored_node?(node)
|
220
|
+
|
221
|
+
case node.name
|
222
|
+
when :include, :prepend, :extend
|
223
|
+
case node.receiver
|
224
|
+
when nil, Prism::SelfNode
|
225
|
+
comment = comments.delete(node.location.start_line - 1)
|
226
|
+
app = application_annotation(node)
|
227
|
+
|
228
|
+
current_class_module_decl!.members << AST::Members::RubyMixin.new(node, comment, app)
|
229
|
+
|
230
|
+
return
|
231
|
+
end
|
232
|
+
when :attr_reader, :attr_accessor, :attr_writer
|
233
|
+
case node.receiver
|
234
|
+
when nil, Prism::SelfNode
|
235
|
+
comment = comments.delete(node.location.start_line - 1)
|
236
|
+
|
237
|
+
comment_line, assertion_comment = comments.find do |_, comment|
|
238
|
+
comment.line_range.begin == node.location.end_line
|
239
|
+
end
|
240
|
+
if assertion_comment && comment_line
|
241
|
+
comments.delete(comment_line)
|
242
|
+
assertion = assertion_comment.annotations.find do |annotation|
|
243
|
+
annotation.is_a?(AST::Annotations::Assertion)
|
244
|
+
end #: AST::Annotations::Assertion?
|
245
|
+
end
|
246
|
+
|
247
|
+
current_class_module_decl!.members << AST::Members::RubyAttr.new(node, comment, assertion)
|
248
|
+
|
249
|
+
return
|
250
|
+
end
|
251
|
+
when :public, :private
|
252
|
+
case node.receiver
|
253
|
+
when nil, Prism::SelfNode
|
254
|
+
if node.arguments && node.arguments.arguments.size > 0
|
255
|
+
if node.name == :public
|
256
|
+
push_visibility(:public) { super }
|
257
|
+
end
|
258
|
+
|
259
|
+
if node.name == :private
|
260
|
+
push_visibility(:private) { super }
|
261
|
+
end
|
262
|
+
|
263
|
+
return
|
264
|
+
else
|
265
|
+
if node.name == :public
|
266
|
+
current_class_module_decl!.members << AST::Members::RubyPublic.new(node)
|
267
|
+
return
|
268
|
+
end
|
269
|
+
|
270
|
+
if node.name == :private
|
271
|
+
current_class_module_decl!.members << AST::Members::RubyPrivate.new(node)
|
272
|
+
return
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
super
|
279
|
+
end
|
280
|
+
|
281
|
+
# @rbs new_visibility: RBS::AST::Members::visibility?
|
282
|
+
# @rbs block: ^() -> void
|
283
|
+
# @rbs returns void
|
284
|
+
def push_visibility(new_visibility, &block)
|
285
|
+
old_visibility = current_visibility
|
286
|
+
|
287
|
+
begin
|
288
|
+
@current_visibility = new_visibility
|
289
|
+
yield
|
290
|
+
ensure
|
291
|
+
@current_visibility = old_visibility
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
# @rbs node: Node
|
296
|
+
# @rbs returns bool
|
297
|
+
def ignored_node?(node)
|
298
|
+
if comment = comments.fetch(node.location.start_line - 1, nil)
|
299
|
+
comment.annotations.any? { _1.is_a?(AST::Annotations::Skip) }
|
300
|
+
else
|
301
|
+
false
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
# Fetch Application annotation which is associated to `node`
|
306
|
+
#
|
307
|
+
# The application annotation is removed from `comments`.
|
308
|
+
#
|
309
|
+
# @rbs node: Node
|
310
|
+
# @rbs returns AST::Annotations::Application?
|
311
|
+
def application_annotation(node)
|
312
|
+
comment_line, app_comment = comments.find do |_, comment|
|
313
|
+
comment.line_range.begin == node.location.end_line
|
314
|
+
end
|
315
|
+
|
316
|
+
if app_comment && comment_line
|
317
|
+
comments.delete(comment_line)
|
318
|
+
app_comment.annotations.find do |annotation|
|
319
|
+
annotation.is_a?(AST::Annotations::Application)
|
320
|
+
end #: AST::Annotations::Application?
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# Fetch Assertion annotation which is associated to `node`
|
325
|
+
#
|
326
|
+
# The assertion annotation is removed from `comments`.
|
327
|
+
#
|
328
|
+
# @rbs node: Node | Location
|
329
|
+
# @rbs returns AST::Annotations::Assertion?
|
330
|
+
def assertion_annotation(node)
|
331
|
+
if node.is_a?(Prism::Location)
|
332
|
+
location = node
|
333
|
+
else
|
334
|
+
location = node.location
|
335
|
+
end
|
336
|
+
comment_line, app_comment = comments.find do |_, comment|
|
337
|
+
comment.line_range.begin == location.end_line
|
338
|
+
end
|
339
|
+
|
340
|
+
if app_comment && comment_line
|
341
|
+
comments.delete(comment_line)
|
342
|
+
app_comment.annotations.find do |annotation|
|
343
|
+
annotation.is_a?(AST::Annotations::Assertion)
|
344
|
+
end #: AST::Annotations::Assertion?
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
# @rbs override
|
349
|
+
def visit_constant_write_node(node)
|
350
|
+
return if ignored_node?(node)
|
351
|
+
|
352
|
+
comment = comments.delete(node.location.start_line - 1)
|
353
|
+
assertion = assertion_annotation(node)
|
354
|
+
|
355
|
+
decl = AST::Declarations::ConstantDecl.new(node, comment, assertion)
|
356
|
+
push_class_module_decl(decl)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|