Skip to content

Commit d1adf91

Browse files
soutaroclaude
andcommitted
Refactor rbs annotate to use Rewriter instead of Writer
Replace AST mutation + Writer serialization with Rewriter-based comment editing, preserving non-documentation comments and original formatting in annotated RBS files. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b8c0aee commit d1adf91

3 files changed

Lines changed: 86 additions & 89 deletions

File tree

lib/rbs/annotate/rdoc_annotator.rb

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,21 @@ def initialize(source:)
1414
end
1515

1616
def annotate_file(path, preserve:)
17-
content = path.read()
17+
buffer, _, decls = Parser.parse_signature(path.read())
1818

19-
_, _, decls = Parser.parse_signature(content)
19+
rewriter = Rewriter.new(buffer)
20+
annotate_decls(decls, rewriter)
2021

21-
annotate_decls(decls)
22-
23-
path.open("w") do |io|
24-
Writer.new(out: io).preserve!(preserve: preserve).write(decls)
25-
end
22+
path.write(rewriter.string)
2623
end
2724

28-
def annotate_decls(decls, outer: [])
25+
def annotate_decls(decls, rewriter, outer: [])
2926
decls.each do |decl|
3027
case decl
3128
when AST::Declarations::Class, AST::Declarations::Module
32-
annotate_class(decl, outer: outer)
29+
annotate_class(decl, rewriter, outer: outer)
3330
when AST::Declarations::Constant
34-
annotate_constant(decl, outer: outer)
31+
annotate_constant(decl, rewriter, outer: outer)
3532
end
3633
end
3734
end
@@ -244,44 +241,44 @@ def doc_for_attribute(typename, attr_name, require: nil, singleton:, tester:)
244241
end
245242
end
246243

247-
def annotate_class(decl, outer:)
244+
def annotate_class(decl, rewriter, outer:)
248245
annots = annotations(decl)
249246

250247
full_name = resolve_name(decl.name, outer: outer)
251248
unless annots.skip?
252249
text = resolve_doc_source(annots.copy_annotation, tester: annots) { doc_for_class(full_name, tester: annots) }
253250
end
254251

255-
replace_comment(decl, text)
252+
replace_comment(decl, text, rewriter)
256253

257254
unless annots.skip_all?
258255
outer_ = outer + [decl.name.to_namespace]
259256

260257
decl.each_member do |member|
261258
case member
262259
when AST::Members::MethodDefinition
263-
annotate_method(full_name, member)
260+
annotate_method(full_name, member, rewriter)
264261
when AST::Members::Alias
265-
annotate_alias(full_name, member)
262+
annotate_alias(full_name, member, rewriter)
266263
when AST::Members::AttrReader, AST::Members::AttrAccessor, AST::Members::AttrWriter
267-
annotate_attribute(full_name, member)
264+
annotate_attribute(full_name, member, rewriter)
268265
end
269266
end
270267

271-
annotate_decls(decl.each_decl.to_a, outer: outer_)
268+
annotate_decls(decl.each_decl.to_a, rewriter, outer: outer_)
272269
end
273270
end
274271

275-
def annotate_constant(const, outer:)
272+
def annotate_constant(const, rewriter, outer:)
276273
annots = Annotations.new([])
277274

278275
full_name = resolve_name(const.name, outer: outer)
279276
text = doc_for_constant(full_name, tester: annots)
280277

281-
replace_comment(const, text)
278+
replace_comment(const, text, rewriter)
282279
end
283280

284-
def annotate_alias(typename, als)
281+
def annotate_alias(typename, als, rewriter)
285282
annots = annotations(als)
286283

287284
unless annots.skip?
@@ -295,7 +292,7 @@ def annotate_alias(typename, als)
295292
end
296293
end
297294

298-
replace_comment(als, text)
295+
replace_comment(als, text, rewriter)
299296
end
300297

301298
def join_docs(docs, separator: "----")
@@ -311,7 +308,7 @@ def join_docs(docs, separator: "----")
311308
end
312309
end
313310

314-
def annotate_method(typename, method)
311+
def annotate_method(typename, method, rewriter)
315312
annots = annotations(method)
316313

317314
unless annots.skip?
@@ -337,10 +334,10 @@ def annotate_method(typename, method)
337334
}
338335
end
339336

340-
replace_comment(method, text)
337+
replace_comment(method, text, rewriter)
341338
end
342339

343-
def annotate_attribute(typename, attr)
340+
def annotate_attribute(typename, attr, rewriter)
344341
annots = annotations(attr)
345342

346343
unless annots.skip?
@@ -368,18 +365,17 @@ def annotate_attribute(typename, attr)
368365
end
369366
end
370367

371-
replace_comment(attr, text)
368+
replace_comment(attr, text, rewriter)
372369
end
373370

374-
def replace_comment(commented, string)
371+
def replace_comment(commented, string, rewriter)
375372
if string
376373
if string.empty?
377-
commented.instance_variable_set(:@comment, nil)
374+
rewriter.delete_comment(commented.comment) if commented.comment
375+
elsif commented.comment
376+
rewriter.replace_comment(commented.comment, content: string)
378377
else
379-
commented.instance_variable_set(
380-
:@comment,
381-
AST::Comment.new(location: nil, string: string)
382-
)
378+
rewriter.add_comment(commented.location || raise, *commented.annotations.filter_map(&:location), content: string)
383379
end
384380
end
385381
end

sig/annotate/rdoc_annotater.rbs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ module RBS
1010

1111
def annotate_file: (Pathname, preserve: bool) -> void
1212

13-
def annotate_decls: (Array[AST::Declarations::t], ?outer: Array[Namespace]) -> void
13+
def annotate_decls: (Array[AST::Declarations::t], Rewriter, ?outer: Array[Namespace]) -> void
1414

1515
interface _PathTester
1616
def test_path: (String) -> bool
@@ -50,15 +50,15 @@ module RBS
5050

5151
def resolve_doc_source: (Annotations::Copy?, tester: _PathTester) { () -> String? } -> String?
5252

53-
def annotate_class: (AST::Declarations::Class | AST::Declarations::Module, outer: Array[Namespace]) -> void
53+
def annotate_class: (AST::Declarations::Class | AST::Declarations::Module, Rewriter, outer: Array[Namespace]) -> void
5454

55-
def annotate_constant: (AST::Declarations::Constant, outer: Array[Namespace]) -> void
55+
def annotate_constant: (AST::Declarations::Constant, Rewriter, outer: Array[Namespace]) -> void
5656

57-
def annotate_method: (TypeName, AST::Members::MethodDefinition) -> void
57+
def annotate_method: (TypeName, AST::Members::MethodDefinition, Rewriter) -> void
5858

59-
def annotate_alias: (TypeName, AST::Members::Alias) -> void
59+
def annotate_alias: (TypeName, AST::Members::Alias, Rewriter) -> void
6060

61-
def annotate_attribute: (TypeName, AST::Members::AttrReader | AST::Members::AttrWriter | AST::Members::AttrAccessor) -> void
61+
def annotate_attribute: (TypeName, AST::Members::AttrReader | AST::Members::AttrWriter | AST::Members::AttrAccessor, Rewriter) -> void
6262

6363
def annotations: (_Annotated) -> Annotations
6464

@@ -70,10 +70,12 @@ module RBS
7070
# - If empty string is given as `comment`, it deletes the original comment.
7171
# - If `nil` is given as `comment`, it keeps the original comment.
7272
#
73-
def replace_comment: (Object & _Commented, String? comment) -> void
73+
def replace_comment: (_Commented, String?, Rewriter) -> void
7474

7575
interface _Commented
76-
def comment: () -> AST::Comment?
76+
%a{pure} def comment: () -> AST::Comment?
77+
%a{pure} def location: () -> Location[untyped, untyped]?
78+
def annotations: () -> Array[AST::Annotation]
7779
end
7880

7981
def resolve_name: (TypeName, outer: Array[Namespace]) -> TypeName

0 commit comments

Comments
 (0)