docscribe 1.4.2 → 1.5.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +465 -130
  3. data/lib/docscribe/cli/check_for_comments.rb +183 -0
  4. data/lib/docscribe/cli/config_builder.rb +107 -53
  5. data/lib/docscribe/cli/formatters/json.rb +294 -0
  6. data/lib/docscribe/cli/formatters/sarif.rb +235 -0
  7. data/lib/docscribe/cli/formatters/text.rb +208 -0
  8. data/lib/docscribe/cli/formatters.rb +26 -0
  9. data/lib/docscribe/cli/generate.rb +45 -45
  10. data/lib/docscribe/cli/init.rb +14 -6
  11. data/lib/docscribe/cli/options.rb +190 -88
  12. data/lib/docscribe/cli/rbs_gen.rb +529 -0
  13. data/lib/docscribe/cli/run.rb +210 -152
  14. data/lib/docscribe/cli/sigs.rb +366 -0
  15. data/lib/docscribe/cli/update_types.rb +103 -0
  16. data/lib/docscribe/cli.rb +21 -13
  17. data/lib/docscribe/config/defaults.rb +5 -1
  18. data/lib/docscribe/config/emit.rb +17 -0
  19. data/lib/docscribe/config/filtering.rb +18 -25
  20. data/lib/docscribe/config/loader.rb +15 -11
  21. data/lib/docscribe/config/plugin.rb +1 -1
  22. data/lib/docscribe/config/rbs.rb +41 -9
  23. data/lib/docscribe/config/sorbet.rb +9 -12
  24. data/lib/docscribe/config/sorting.rb +1 -1
  25. data/lib/docscribe/config/template.rb +9 -1
  26. data/lib/docscribe/config/utils.rb +11 -9
  27. data/lib/docscribe/config.rb +2 -4
  28. data/lib/docscribe/infer/ast_walk.rb +1 -1
  29. data/lib/docscribe/infer/literals.rb +6 -11
  30. data/lib/docscribe/infer/names.rb +2 -3
  31. data/lib/docscribe/infer/params.rb +15 -17
  32. data/lib/docscribe/infer/raises.rb +3 -5
  33. data/lib/docscribe/infer/returns.rb +542 -140
  34. data/lib/docscribe/infer.rb +22 -23
  35. data/lib/docscribe/inline_rewriter/collector.rb +159 -164
  36. data/lib/docscribe/inline_rewriter/doc_block.rb +145 -115
  37. data/lib/docscribe/inline_rewriter/doc_builder.rb +1026 -723
  38. data/lib/docscribe/inline_rewriter/source_helpers.rb +49 -49
  39. data/lib/docscribe/inline_rewriter/tag_sorter.rb +82 -85
  40. data/lib/docscribe/inline_rewriter.rb +495 -492
  41. data/lib/docscribe/parsing.rb +29 -10
  42. data/lib/docscribe/plugin/base/collector_plugin.rb +2 -1
  43. data/lib/docscribe/plugin/base/tag_plugin.rb +0 -1
  44. data/lib/docscribe/plugin/context.rb +28 -18
  45. data/lib/docscribe/plugin/registry.rb +26 -27
  46. data/lib/docscribe/plugin/tag.rb +9 -14
  47. data/lib/docscribe/plugin.rb +17 -16
  48. data/lib/docscribe/types/provider_chain.rb +4 -2
  49. data/lib/docscribe/types/rbs/collection_loader.rb +2 -2
  50. data/lib/docscribe/types/rbs/provider.rb +60 -44
  51. data/lib/docscribe/types/rbs/type_formatter.rb +224 -83
  52. data/lib/docscribe/types/signature.rb +22 -42
  53. data/lib/docscribe/types/sorbet/base_provider.rb +24 -19
  54. data/lib/docscribe/types/sorbet/rbi_provider.rb +3 -3
  55. data/lib/docscribe/types/sorbet/source_provider.rb +3 -2
  56. data/lib/docscribe/types/yard/formatter.rb +100 -0
  57. data/lib/docscribe/types/yard/parser.rb +240 -0
  58. data/lib/docscribe/types/yard/types.rb +52 -0
  59. data/lib/docscribe/version.rb +1 -1
  60. metadata +33 -1
@@ -12,8 +12,8 @@ module Docscribe
12
12
 
13
13
  # Extract the method name from a `:def` or `:defs` node.
14
14
  #
15
- # @note module_function: when included, also defines #node_name (instance visibility: private)
16
- # @param [Parser::AST::Node] node
15
+ # @note module_function: defines #node_name (visibility: private)
16
+ # @param [Parser::AST::Node] node def or defs AST node
17
17
  # @return [Symbol, nil]
18
18
  def node_name(node)
19
19
  case node.type
@@ -26,9 +26,9 @@ module Docscribe
26
26
  #
27
27
  # Used as the insertion point for generated documentation.
28
28
  #
29
- # @note module_function: when included, also defines #line_start_range (instance visibility: private)
30
- # @param [Parser::Source::Buffer] buffer
31
- # @param [Parser::AST::Node] node
29
+ # @note module_function: defines #line_start_range (visibility: private)
30
+ # @param [Parser::Source::Buffer] buffer source buffer for range
31
+ # @param [Parser::AST::Node] node target AST node
32
32
  # @return [Parser::Source::Range]
33
33
  def line_start_range(buffer, node)
34
34
  start_pos = node.loc.expression.begin_pos
@@ -47,10 +47,10 @@ module Docscribe
47
47
  #
48
48
  # Returns nil if no doc-like block is present.
49
49
  #
50
- # @note module_function: when included, also defines #doc_comment_block_info (instance visibility: private)
51
- # @param [Parser::Source::Buffer] buffer
50
+ # @note module_function: defines #doc_comment_block_info (visibility: private)
51
+ # @param [Parser::Source::Buffer] buffer source buffer to scan
52
52
  # @param [Integer] def_bol_pos beginning-of-line position of the target def
53
- # @return [Hash, nil]
53
+ # @return [Hash<Symbol, Array<String>, Integer, nil>, nil]
54
54
  def doc_comment_block_info(buffer, def_bol_pos)
55
55
  lines = buffer.source.lines
56
56
  def_line_idx = (buffer.source[0...def_bol_pos] || '').count("\n")
@@ -70,8 +70,8 @@ module Docscribe
70
70
  # Preserved directive lines (such as RuboCop directives or magic comments) are excluded
71
71
  # from the returned range.
72
72
  #
73
- # @note module_function: when included, also defines #comment_block_removal_range (instance visibility: private)
74
- # @param [Parser::Source::Buffer] buffer
73
+ # @note module_function: defines #comment_block_removal_range (visibility: private)
74
+ # @param [Parser::Source::Buffer] buffer source buffer to scan
75
75
  # @param [Integer] def_bol_pos beginning-of-line position of the target def
76
76
  # @return [Parser::Source::Range, nil]
77
77
  def comment_block_removal_range(buffer, def_bol_pos)
@@ -92,10 +92,10 @@ module Docscribe
92
92
  # Walks upward from def_line_idx, skipping blank lines, then includes all
93
93
  # contiguous comment lines.
94
94
  #
95
- # @note module_function: when included, also defines #find_comment_block_range (instance visibility: private)
96
- # @param [Array<String>] lines
97
- # @param [Integer] def_line_idx
98
- # @return [Hash{start_idx: Integer, end_idx: Integer}, nil]
95
+ # @note module_function: defines #find_comment_block_range (visibility: private)
96
+ # @param [Array<String>] lines source code lines
97
+ # @param [Integer] def_line_idx def line index
98
+ # @return [Hash<Symbol, Integer>, nil]
99
99
  def find_comment_block_range(lines, def_line_idx)
100
100
  i = def_line_idx - 1
101
101
 
@@ -113,10 +113,10 @@ module Docscribe
113
113
  #
114
114
  # Preserved lines include RuboCop directives and Ruby magic comments.
115
115
  #
116
- # @note module_function: when included, also defines #find_preserved_start_idx (instance visibility: private)
117
- # @param [Array<String>] lines
118
- # @param [Integer] start_idx
119
- # @param [Integer] end_idx
116
+ # @note module_function: defines #find_preserved_start_idx (visibility: private)
117
+ # @param [Array<String>] lines source code lines
118
+ # @param [Integer] start_idx block start index
119
+ # @param [Integer] end_idx block end index
120
120
  # @return [Integer]
121
121
  def find_preserved_start_idx(lines, start_idx, end_idx)
122
122
  idx = start_idx
@@ -126,9 +126,9 @@ module Docscribe
126
126
 
127
127
  # Whether a comment block range contains documentation markers.
128
128
  #
129
- # @note module_function: when included, also defines #doc_marker? (instance visibility: private)
130
- # @param [Array<String>] lines
131
- # @param [Range] range line index range
129
+ # @note module_function: defines #doc_marker? (visibility: private)
130
+ # @param [Array<String>] lines source code lines
131
+ # @param [Range<Integer>] range line index range
132
132
  # @return [Boolean]
133
133
  def doc_marker?(lines, range)
134
134
  (lines[range] || []).any? { |line| doc_marker_line?(line) }
@@ -136,12 +136,12 @@ module Docscribe
136
136
 
137
137
  # Build block info hash from computed line ranges.
138
138
  #
139
- # @note module_function: when included, also defines #build_block_info (instance visibility: private)
140
- # @param [Array<String>] lines
141
- # @param [Integer] start_idx
142
- # @param [Integer] preserved_start_idx
143
- # @param [Integer] end_idx
144
- # @return [Hash]
139
+ # @note module_function: defines #build_block_info (visibility: private)
140
+ # @param [Array<String>] lines source code lines
141
+ # @param [Integer] start_idx block start index
142
+ # @param [Integer] preserved_start_idx preserved start index
143
+ # @param [Integer] end_idx block end index
144
+ # @return [Hash<Symbol, Array<String>, Integer, nil>]
145
145
  def build_block_info(lines, start_idx, preserved_start_idx, end_idx)
146
146
  positions = compute_positions(lines, start_idx, preserved_start_idx, end_idx)
147
147
  {
@@ -154,11 +154,11 @@ module Docscribe
154
154
 
155
155
  # Compute the removal range for preserved start position.
156
156
  #
157
- # @note module_function: when included, also defines #compute_removal_range (instance visibility: private)
158
- # @param [Parser::Source::Buffer] buffer
159
- # @param [Array<String>] lines
160
- # @param [Integer] preserved_start_idx
161
- # @param [Integer] def_bol_pos
157
+ # @note module_function: defines #compute_removal_range (visibility: private)
158
+ # @param [Parser::Source::Buffer] buffer source buffer for position
159
+ # @param [Array<String>] lines source code lines
160
+ # @param [Integer] preserved_start_idx preserved start index
161
+ # @param [Integer] def_bol_pos beginning-of-line position of the target def
162
162
  # @return [Parser::Source::Range]
163
163
  def compute_removal_range(buffer, lines, preserved_start_idx, def_bol_pos)
164
164
  start_pos = preserved_start_idx.positive? ? (lines[0...preserved_start_idx] || []).join.length : 0
@@ -167,12 +167,12 @@ module Docscribe
167
167
 
168
168
  # Compute source positions for a comment block.
169
169
  #
170
- # @note module_function: when included, also defines #compute_positions (instance visibility: private)
171
- # @param [Array<String>] lines
172
- # @param [Integer] start_idx
173
- # @param [Integer] doc_start_idx
174
- # @param [Integer] end_pos_idx
175
- # @return [Hash{start_pos: Integer, doc_start_pos: Integer, end_pos: Integer}]
170
+ # @note module_function: defines #compute_positions (visibility: private)
171
+ # @param [Array<String>] lines source code lines
172
+ # @param [Integer] start_idx block start index
173
+ # @param [Integer] doc_start_idx doc content start index
174
+ # @param [Integer] end_pos_idx block end position index
175
+ # @return [Hash<Symbol, Integer>]
176
176
  def compute_positions(lines, start_idx, doc_start_idx, end_pos_idx)
177
177
  start_pos = start_idx.positive? ? (lines[0...start_idx] || []).join.length : 0
178
178
  doc_start_pos = doc_start_idx.positive? ? (lines[0...doc_start_idx] || []).join.length : 0
@@ -187,8 +187,8 @@ module Docscribe
187
187
  # - Ruby magic comments
188
188
  # - tool directives such as `:nocov:` / `:stopdoc:`
189
189
  #
190
- # @note module_function: when included, also defines #preserved_comment_line? (instance visibility: private)
191
- # @param [String] line
190
+ # @note module_function: defines #preserved_comment_line? (visibility: private)
191
+ # @param [String] line comment line to check
192
192
  # @return [Boolean]
193
193
  def preserved_comment_line?(line)
194
194
  # RuboCop directives
@@ -213,8 +213,8 @@ module Docscribe
213
213
  # - Docscribe header lines
214
214
  # - YARD tags/directives beginning with `@`
215
215
  #
216
- # @note module_function: when included, also defines #doc_marker_line? (instance visibility: private)
217
- # @param [String] line
216
+ # @note module_function: defines #doc_marker_line? (visibility: private)
217
+ # @param [String] line comment line to check
218
218
  # @return [Boolean]
219
219
  def doc_marker_line?(line)
220
220
  # Docscribe header line:
@@ -238,10 +238,9 @@ module Docscribe
238
238
  #
239
239
  # This helper is retained for compatibility/legacy behavior checks.
240
240
  #
241
- # @note module_function: when included, also defines #already_has_doc_immediately_above?
242
- # (instance visibility: private)
243
- # @param [Parser::Source::Buffer] buffer
244
- # @param [Integer] insert_pos
241
+ # @note module_function: defines #already_has_doc_immediately_above? (visibility: private)
242
+ # @param [Parser::Source::Buffer] buffer source buffer to check
243
+ # @param [Integer] insert_pos insertion position
245
244
  # @return [Boolean]
246
245
  def already_has_doc_immediately_above?(buffer, insert_pos)
247
246
  src = buffer.source
@@ -258,10 +257,11 @@ module Docscribe
258
257
  #
259
258
  # Tabs and spaces are preserved exactly.
260
259
  #
261
- # @note module_function: when included, also defines #line_indent (instance visibility: private)
262
- # @param [Parser::AST::Node] node
260
+ # @note module_function: defines #line_indent (visibility: private)
261
+ # @param [Parser::AST::Node] node target AST node
263
262
  # @raise [StandardError]
264
- # @return [String]
263
+ # @return [String] if StandardError
264
+ # @return [String] if StandardError
265
265
  def line_indent(node)
266
266
  line = node.loc.expression.source_line
267
267
  return '' unless line
@@ -11,33 +11,30 @@ module Docscribe
11
11
  module TagSorter
12
12
  module_function
13
13
 
14
- # One sortable top-level tag entry plus its continuation lines.
15
14
  # @!attribute [rw] tag
16
- # @return [Object]
17
- # @param [Object] value
15
+ # @return [String]
16
+ # @param [String] value
18
17
  #
19
18
  # @!attribute [rw] lines
20
- # @return [Object]
21
- # @param [Object] value
19
+ # @return [Array<String>]
20
+ # @param [Array<String>] value
22
21
  #
23
22
  # @!attribute [rw] param_name
24
- # @return [Object]
25
- # @param [Object] value
23
+ # @return [String?]
24
+ # @param [String?] value
26
25
  #
27
26
  # @!attribute [rw] option_owner
28
- # @return [Object]
29
- # @param [Object] value
27
+ # @return [String?]
28
+ # @param [String?] value
30
29
  #
31
30
  # @!attribute [rw] index
32
- # @return [Object]
33
- # @param [Object] value
31
+ # @return [Integer]
32
+ # @param [Integer] value
34
33
  Entry = Struct.new(:tag, :lines, :param_name, :option_owner, :index, keyword_init: true)
35
34
 
36
- # Sort contiguous top-level tag runs according to configured tag order.
35
+ # Sort
37
36
  #
38
- # Non-tag content is preserved as-is and acts as a sort boundary.
39
- #
40
- # @note module_function: when included, also defines #sort (instance visibility: private)
37
+ # @note module_function: defines #sort (visibility: private)
41
38
  # @param [Array<String>] lines comment block lines
42
39
  # @param [Array<String>] tag_order configured tag order
43
40
  # @return [Array<String>]
@@ -47,22 +44,22 @@ module Docscribe
47
44
  segments.flat_map { |seg| sort_segment(seg, priority: priority) }
48
45
  end
49
46
 
50
- # Build a tag priority map from configured tag order.
47
+ # Build priority
51
48
  #
52
- # @note module_function: when included, also defines #build_priority (instance visibility: private)
53
- # @param [Array<String>] tag_order
54
- # @return [Hash{String=>Integer}]
49
+ # @note module_function: defines #build_priority (visibility: private)
50
+ # @param [Array<String>] tag_order configured tag order
51
+ # @return [Hash<String, Integer>]
55
52
  def build_priority(tag_order)
56
53
  Array(tag_order).map { |t| t.to_s.sub(/\A@/, '') }
57
54
  .each_with_index
58
55
  .to_h
59
56
  end
60
57
 
61
- # Parse lines into sortable tag-run segments and non-sortable segments.
58
+ # Parse segments
62
59
  #
63
- # @note module_function: when included, also defines #parse_segments (instance visibility: private)
64
- # @param [Array<String>] lines
65
- # @return [Array<Hash>]
60
+ # @note module_function: defines #parse_segments (visibility: private)
61
+ # @param [Array<String>] lines comment block lines
62
+ # @return [Array<Hash<Symbol, Object>>]
66
63
  def parse_segments(lines)
67
64
  segments = [] #: Array[untyped]
68
65
  i = 0
@@ -72,12 +69,12 @@ module Docscribe
72
69
  segments
73
70
  end
74
71
 
75
- # Parse the next line as either a tag run or non-tag content, appending to segments.
72
+ # Advance parse
76
73
  #
77
- # @note module_function: when included, also defines #advance_parse (instance visibility: private)
74
+ # @note module_function: defines #advance_parse (visibility: private)
78
75
  # @param [Array<String>] lines comment block lines
79
76
  # @param [Integer] idx current parse index
80
- # @param [Array<Hash>] segments accumulated parsed segments
77
+ # @param [Array<Hash<Symbol, Object>>] segments accumulated parsed segments
81
78
  # @return [Integer] new index after processing
82
79
  def advance_parse(lines, idx, segments)
83
80
  if top_level_tag_line?(lines[idx])
@@ -88,12 +85,12 @@ module Docscribe
88
85
  end
89
86
  end
90
87
 
91
- # Consume a contiguous tag run and append to segments.
88
+ # Consume tag run
92
89
  #
93
- # @note module_function: when included, also defines #consume_tag_run (instance visibility: private)
94
- # @param [Array<String>] lines
90
+ # @note module_function: defines #consume_tag_run (visibility: private)
91
+ # @param [Array<String>] lines comment block lines
95
92
  # @param [Integer] idx current index
96
- # @param [Array<Hash>] segments accumulated segments
93
+ # @param [Array<Hash<Symbol, Object>>] segments accumulated segments
97
94
  # @return [Integer] new index after consuming the run
98
95
  def consume_tag_run(lines, idx, segments)
99
96
  entries = [] #: Array[untyped]
@@ -105,11 +102,11 @@ module Docscribe
105
102
  idx
106
103
  end
107
104
 
108
- # Sort one parsed segment if it is a tag run.
105
+ # Sort segment
109
106
  #
110
- # @note module_function: when included, also defines #sort_segment (instance visibility: private)
111
- # @param [Hash] segment
112
- # @param [Hash{String=>Integer}] priority
107
+ # @note module_function: defines #sort_segment (visibility: private)
108
+ # @param [Hash<Symbol, Object>] segment parsed comment segment
109
+ # @param [Hash<String, Integer>] priority tag priority map
113
110
  # @return [Array<String>]
114
111
  def sort_segment(segment, priority:)
115
112
  return segment[:lines] unless segment[:type] == :tag_run
@@ -123,26 +120,26 @@ module Docscribe
123
120
  .flat_map(&:lines)
124
121
  end
125
122
 
126
- # Compute sort priority for a grouped tag entry.
123
+ # Group priority
127
124
  #
128
- # @note module_function: when included, also defines #group_priority (instance visibility: private)
129
- # @param [Array<Entry>] group
130
- # @param [Hash{String=>Integer}] priority
125
+ # @note module_function: defines #group_priority (visibility: private)
126
+ # @param [Array<Docscribe::InlineRewriter::TagSorter::Entry>] group entry group array
127
+ # @param [Hash<String, Integer>] priority tag priority map
131
128
  # @return [Integer]
132
129
  def group_priority(group, priority)
133
130
  first = group.first
134
131
  priority.fetch(first.tag, priority.length)
135
132
  end
136
133
 
137
- # Consume one top-level tag entry and its continuation lines.
134
+ # Consume entry
138
135
  #
139
- # @note module_function: when included, also defines #consume_entry (instance visibility: private)
140
- # @param [Array<String>] lines
141
- # @param [Integer] start_idx
142
- # @return [Array<(Entry, Integer)>]
136
+ # @note module_function: defines #consume_entry (visibility: private)
137
+ # @param [Array<String>] lines comment block lines
138
+ # @param [Integer] start_idx original index of the first line
139
+ # @return [(Docscribe::InlineRewriter::TagSorter::Entry, Integer)]
143
140
  def consume_entry(lines, start_idx)
144
141
  first = lines[start_idx]
145
- tag = extract_tag_name(first)
142
+ tag = extract_tag_name(first) || ''
146
143
  entry_lines = collect_continuation_lines(lines, start_idx + 1)
147
144
  i = entry_lines.length + start_idx
148
145
 
@@ -151,14 +148,14 @@ module Docscribe
151
148
  [entry, i]
152
149
  end
153
150
 
154
- # Build an Entry struct from parsed tag name, lines, and source line metadata.
151
+ # Build entry
155
152
  #
156
- # @note module_function: when included, also defines #build_entry (instance visibility: private)
157
- # @param [String, nil] tag the extracted tag name
153
+ # @note module_function: defines #build_entry (visibility: private)
154
+ # @param [String] tag the extracted tag name
158
155
  # @param [Array<String>] entry_lines all lines belonging to this entry
159
156
  # @param [String] first the first (tag) line
160
157
  # @param [Integer] start_idx original index of the first line
161
- # @return [Entry]
158
+ # @return [Docscribe::InlineRewriter::TagSorter::Entry]
162
159
  def build_entry(tag, entry_lines, first, start_idx)
163
160
  Entry.new(
164
161
  tag: tag,
@@ -169,11 +166,11 @@ module Docscribe
169
166
  )
170
167
  end
171
168
 
172
- # Collect continuation lines following a top-level tag entry.
169
+ # Collect continuation lines
173
170
  #
174
- # @note module_function: when included, also defines #collect_continuation_lines (instance visibility: private)
175
- # @param [Array<String>] lines
176
- # @param [Integer] start_idx
171
+ # @note module_function: defines #collect_continuation_lines (visibility: private)
172
+ # @param [Array<String>] lines comment block lines
173
+ # @param [Integer] start_idx original index of the first line
177
174
  # @return [Array<String>]
178
175
  def collect_continuation_lines(lines, start_idx)
179
176
  result = [] #: Array[String]
@@ -190,11 +187,11 @@ module Docscribe
190
187
  result
191
188
  end
192
189
 
193
- # Group entries so `@option` tags remain attached to their owning `@param`.
190
+ # Group entries
194
191
  #
195
- # @note module_function: when included, also defines #group_entries (instance visibility: private)
196
- # @param [Array<Entry>] entries
197
- # @return [Array<Array<Entry>>]
192
+ # @note module_function: defines #group_entries (visibility: private)
193
+ # @param [Array<Docscribe::InlineRewriter::TagSorter::Entry>] entries parsed tag entries
194
+ # @return [Array<Array<Docscribe::InlineRewriter::TagSorter::Entry>>]
198
195
  def group_entries(entries)
199
196
  groups = [] #: Array[untyped]
200
197
  i = 0
@@ -207,28 +204,28 @@ module Docscribe
207
204
  groups
208
205
  end
209
206
 
210
- # Group a single entry, attaching any subsequent @option entries if it is a @param.
207
+ # Group entry
211
208
  #
212
- # @note module_function: when included, also defines #group_entry (instance visibility: private)
213
- # @param [Array<Entry>] entries parsed tag entries
209
+ # @note module_function: defines #group_entry (visibility: private)
210
+ # @param [Array<Docscribe::InlineRewriter::TagSorter::Entry>] entries parsed tag entries
214
211
  # @param [Integer] idx index of the entry to group
215
- # @return [Array<Entry>] the entry group
212
+ # @return [Array<Docscribe::InlineRewriter::TagSorter::Entry>] the entry group
216
213
  def group_entry(entries, idx)
217
214
  entry = entries[idx]
218
215
  if entry.tag == 'param'
219
- [entry] + collect_option_entries(entries, idx + 1, entry.param_name)
216
+ [entry] + collect_option_entries(entries, idx + 1, entry.param_name || '')
220
217
  else
221
218
  [entry]
222
219
  end
223
220
  end
224
221
 
225
- # Collect `@option` entries belonging to the given param name.
222
+ # Collect option entries
226
223
  #
227
- # @note module_function: when included, also defines #collect_option_entries (instance visibility: private)
228
- # @param [Array<Entry>] entries
229
- # @param [Integer] start_idx
230
- # @param [String] param_name
231
- # @return [Array<Entry>]
224
+ # @note module_function: defines #collect_option_entries (visibility: private)
225
+ # @param [Array<Docscribe::InlineRewriter::TagSorter::Entry>] entries parsed tag entries
226
+ # @param [Integer] start_idx original index of the first line
227
+ # @param [String] param_name parent param name
228
+ # @return [Array<Docscribe::InlineRewriter::TagSorter::Entry>]
232
229
  def collect_option_entries(entries, start_idx, param_name)
233
230
  result = [] #: Array[untyped]
234
231
  i = start_idx
@@ -244,46 +241,46 @@ module Docscribe
244
241
  result
245
242
  end
246
243
 
247
- # Whether a line begins a top-level tag entry.
244
+ # Top level tag line
248
245
  #
249
- # @note module_function: when included, also defines #top_level_tag_line? (instance visibility: private)
250
- # @param [String] line
246
+ # @note module_function: defines #top_level_tag_line? (visibility: private)
247
+ # @param [String] line comment line to check
251
248
  # @return [Boolean]
252
249
  def top_level_tag_line?(line)
253
250
  !!(line =~ /^\s*#\s*@\w+/)
254
251
  end
255
252
 
256
- # Whether a line is any comment line.
253
+ # Comment line
257
254
  #
258
- # @note module_function: when included, also defines #comment_line? (instance visibility: private)
259
- # @param [String] line
255
+ # @note module_function: defines #comment_line? (visibility: private)
256
+ # @param [String] line comment line to check
260
257
  # @return [Boolean]
261
258
  def comment_line?(line)
262
259
  !!(line =~ /^\s*#/)
263
260
  end
264
261
 
265
- # Whether a line is a blank comment separator.
262
+ # Blank comment line
266
263
  #
267
- # @note module_function: when included, also defines #blank_comment_line? (instance visibility: private)
268
- # @param [String] line
264
+ # @note module_function: defines #blank_comment_line? (visibility: private)
265
+ # @param [String] line comment line to check
269
266
  # @return [Boolean]
270
267
  def blank_comment_line?(line)
271
268
  !!(line =~ /^\s*#\s*$/)
272
269
  end
273
270
 
274
- # Extract tag name from a top-level tag line without the leading `@`.
271
+ # Extract tag name
275
272
  #
276
- # @note module_function: when included, also defines #extract_tag_name (instance visibility: private)
277
- # @param [String] line
273
+ # @note module_function: defines #extract_tag_name (visibility: private)
274
+ # @param [String] line comment line to parse
278
275
  # @return [String, nil]
279
276
  def extract_tag_name(line)
280
277
  line[/^\s*#\s*@(\w+)/, 1]
281
278
  end
282
279
 
283
- # Extract parameter name from a `@param` line.
280
+ # Extract param name
284
281
  #
285
- # @note module_function: when included, also defines #extract_param_name (instance visibility: private)
286
- # @param [String] line
282
+ # @note module_function: defines #extract_param_name (visibility: private)
283
+ # @param [String] line param tag line to parse
287
284
  # @return [String, nil]
288
285
  def extract_param_name(line)
289
286
  return Regexp.last_match(1) if line =~ /^\s*#\s*@param\b\s+\[[^\]]+\]\s+(\S+)/
@@ -292,10 +289,10 @@ module Docscribe
292
289
  nil
293
290
  end
294
291
 
295
- # Extract owning options-hash param name from an `@option` line.
292
+ # Extract option owner
296
293
  #
297
- # @note module_function: when included, also defines #extract_option_owner (instance visibility: private)
298
- # @param [String] line
294
+ # @note module_function: defines #extract_option_owner (visibility: private)
295
+ # @param [String] line option tag line to parse
299
296
  # @return [String, nil]
300
297
  def extract_option_owner(line)
301
298
  line[/^\s*#\s*@option\b\s+(\S+)/, 1]