docscribe 1.4.1 → 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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +588 -104
  3. data/lib/docscribe/cli/check_for_comments.rb +183 -0
  4. data/lib/docscribe/cli/config_builder.rb +180 -36
  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 +296 -125
  10. data/lib/docscribe/cli/init.rb +58 -14
  11. data/lib/docscribe/cli/options.rb +410 -133
  12. data/lib/docscribe/cli/rbs_gen.rb +529 -0
  13. data/lib/docscribe/cli/run.rb +503 -189
  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 +35 -9
  17. data/lib/docscribe/config/defaults.rb +16 -12
  18. data/lib/docscribe/config/emit.rb +18 -0
  19. data/lib/docscribe/config/filtering.rb +37 -31
  20. data/lib/docscribe/config/loader.rb +20 -13
  21. data/lib/docscribe/config/plugin.rb +2 -1
  22. data/lib/docscribe/config/rbs.rb +68 -27
  23. data/lib/docscribe/config/sorbet.rb +40 -17
  24. data/lib/docscribe/config/sorting.rb +2 -1
  25. data/lib/docscribe/config/template.rb +10 -1
  26. data/lib/docscribe/config/utils.rb +12 -9
  27. data/lib/docscribe/config.rb +3 -4
  28. data/lib/docscribe/infer/ast_walk.rb +1 -1
  29. data/lib/docscribe/infer/constants.rb +15 -0
  30. data/lib/docscribe/infer/literals.rb +39 -26
  31. data/lib/docscribe/infer/names.rb +24 -16
  32. data/lib/docscribe/infer/params.rb +57 -13
  33. data/lib/docscribe/infer/raises.rb +23 -15
  34. data/lib/docscribe/infer/returns.rb +784 -199
  35. data/lib/docscribe/infer.rb +28 -28
  36. data/lib/docscribe/inline_rewriter/collector.rb +816 -430
  37. data/lib/docscribe/inline_rewriter/doc_block.rb +323 -150
  38. data/lib/docscribe/inline_rewriter/doc_builder.rb +1837 -648
  39. data/lib/docscribe/inline_rewriter/source_helpers.rb +119 -71
  40. data/lib/docscribe/inline_rewriter/tag_sorter.rb +165 -107
  41. data/lib/docscribe/inline_rewriter.rb +1144 -727
  42. data/lib/docscribe/parsing.rb +29 -10
  43. data/lib/docscribe/plugin/base/collector_plugin.rb +3 -3
  44. data/lib/docscribe/plugin/base/tag_plugin.rb +1 -2
  45. data/lib/docscribe/plugin/context.rb +28 -18
  46. data/lib/docscribe/plugin/registry.rb +49 -23
  47. data/lib/docscribe/plugin/tag.rb +9 -14
  48. data/lib/docscribe/plugin.rb +54 -22
  49. data/lib/docscribe/types/provider_chain.rb +4 -2
  50. data/lib/docscribe/types/rbs/collection_loader.rb +2 -3
  51. data/lib/docscribe/types/rbs/provider.rb +127 -62
  52. data/lib/docscribe/types/rbs/type_formatter.rb +286 -77
  53. data/lib/docscribe/types/signature.rb +22 -42
  54. data/lib/docscribe/types/sorbet/base_provider.rb +51 -27
  55. data/lib/docscribe/types/sorbet/rbi_provider.rb +3 -3
  56. data/lib/docscribe/types/sorbet/source_provider.rb +3 -2
  57. data/lib/docscribe/types/yard/formatter.rb +100 -0
  58. data/lib/docscribe/types/yard/parser.rb +240 -0
  59. data/lib/docscribe/types/yard/types.rb +52 -0
  60. data/lib/docscribe/version.rb +1 -1
  61. metadata +34 -2
@@ -0,0 +1,366 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+ require 'docscribe/parsing'
5
+ require 'docscribe/types/rbs/provider'
6
+
7
+ module Docscribe
8
+ module CLI
9
+ # Check RBS signature coverage for Ruby source files.
10
+ #
11
+ # Usage:
12
+ # docscribe sigs [options] [files...]
13
+ #
14
+ # Parses Ruby source files, extracts method definitions, and checks
15
+ # each method against the configured RBS signature directories.
16
+ # Reports methods that lack RBS type signatures.
17
+ module Sigs
18
+ BANNER = <<~TEXT
19
+ Usage: docscribe sigs [options] [files...]
20
+
21
+ Check RBS signature coverage for Ruby source files.
22
+
23
+ TEXT
24
+
25
+ EXIT_CODES = "\nExit codes:\n " \
26
+ "0 - all methods have signatures\n " \
27
+ "1 - some methods lack signatures\n " \
28
+ '2 - error occurred'
29
+
30
+ # @!attribute [rw] name
31
+ # @return [Symbol]
32
+ # @param [Symbol] value
33
+ #
34
+ # @!attribute [rw] scope
35
+ # @return [Symbol]
36
+ # @param [Symbol] value
37
+ #
38
+ # @!attribute [rw] container
39
+ # @return [String?]
40
+ # @param [String?] value
41
+ #
42
+ # @!attribute [rw] file
43
+ # @return [String]
44
+ # @param [String] value
45
+ #
46
+ # @!attribute [rw] line
47
+ # @return [Integer]
48
+ # @param [Integer] value
49
+ MethodDef = Struct.new(:name, :scope, :container, :file, :line, keyword_init: true)
50
+
51
+ class << self
52
+ # @param [Array<String>] argv
53
+ # @return [Integer]
54
+ def run(argv)
55
+ warn_ruby_version
56
+ options = parse_options(argv)
57
+ paths = expand_paths(argv)
58
+ return no_files_found if paths.empty?
59
+
60
+ run_with(options, extract_methods(paths))
61
+ end
62
+
63
+ private
64
+
65
+ # @private
66
+ # @return [void]
67
+ def warn_ruby_version
68
+ return unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.0')
69
+
70
+ warn 'Warning: docscribe sigs requires Ruby 3.0+ for RBS support. ' \
71
+ "You are running Ruby #{RUBY_VERSION}."
72
+ end
73
+
74
+ # @private
75
+ # @param [Array<String>] argv
76
+ # @return [Hash<Symbol, Object>]
77
+ def parse_options(argv)
78
+ options = { sig_dirs: ['sig'], rbs_collection: false, verbose: false }
79
+
80
+ parser = OptionParser.new do |opts|
81
+ opts.banner = BANNER
82
+ register_sig_options(opts, options)
83
+ end
84
+
85
+ parser.parse!(argv)
86
+ options
87
+ end
88
+
89
+ # @private
90
+ # @param [OptionParser] opts
91
+ # @param [Hash<Symbol, Object>] options
92
+ # @return [void]
93
+ def register_sig_options(opts, options)
94
+ opts.on('-s', '--sig-dir DIR', 'Add RBS signature directory (repeatable)') { |d| options[:sig_dirs] << d }
95
+ opts.on('--rbs-collection', 'Use RBS collection') { options[:rbs_collection] = true }
96
+ opts.on('--verbose', 'Print methods that have signatures too') { options[:verbose] = true }
97
+ opts.on('-h', '--help', 'Show this help') do
98
+ puts opts, EXIT_CODES
99
+ exit 0
100
+ end
101
+ end
102
+
103
+ # @private
104
+ # @param [Array<String>] args
105
+ # @return [Array<String>]
106
+ def expand_paths(args)
107
+ files = [] #: Array[String]
108
+ args = ['.'] if args.empty?
109
+ args.each { |path| expand_single_path(files, path) }
110
+ files.uniq.sort
111
+ end
112
+
113
+ # @private
114
+ # @param [Array<String>] files
115
+ # @param [String] path
116
+ # @return [void]
117
+ def expand_single_path(files, path)
118
+ if File.directory?(path)
119
+ files.concat(Dir.glob(File.join(path, '**', '*.rb')))
120
+ elsif File.file?(path)
121
+ files << path
122
+ else
123
+ warn "Skipping missing path: #{path}"
124
+ end
125
+ end
126
+
127
+ # @private
128
+ # @return [Integer]
129
+ def no_files_found
130
+ warn 'No files found. Pass files or directories (e.g. `docscribe sigs lib`).'
131
+ 2
132
+ end
133
+
134
+ # @private
135
+ # @param [Hash<Symbol, Object>] options
136
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
137
+ # @return [Integer]
138
+ def run_with(options, methods)
139
+ return 0 if methods.empty?
140
+
141
+ provider = build_provider(options)
142
+ return 2 unless provider
143
+
144
+ missing = check_sigs(methods, provider, verbose: options[:verbose])
145
+ report_results(methods, missing)
146
+ missing.empty? ? 0 : 1
147
+ end
148
+
149
+ # @private
150
+ # @param [Array<String>] paths
151
+ # @return [Array<Docscribe::CLI::Sigs::MethodDef>]
152
+ def extract_methods(paths)
153
+ methods = [] #: Array[MethodDef]
154
+ paths.each { |path| extract_methods_from_file(path, methods) }
155
+ methods
156
+ end
157
+
158
+ # @private
159
+ # @param [String] path
160
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
161
+ # @raise [Parser::SyntaxError]
162
+ # @raise [StandardError]
163
+ # @return [void] if StandardError
164
+ # @return [Object] if Parser::SyntaxError
165
+ # @return [Object] if StandardError
166
+ def extract_methods_from_file(path, methods)
167
+ src = File.read(path)
168
+ ast = Docscribe::Parsing.parse(src, file: path)
169
+ return unless ast
170
+
171
+ walk_for_methods(ast, [], methods, path)
172
+ rescue Parser::SyntaxError => e # steep:ignore
173
+ warn "Syntax error in #{path}: #{e.message}"
174
+ rescue StandardError => e
175
+ warn "Error parsing #{path}: #{e.class}: #{e.message}"
176
+ end
177
+
178
+ # @private
179
+ # @param [Parser::AST::Node] node
180
+ # @param [Array<String>] containers
181
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
182
+ # @param [String] path
183
+ # @param [Boolean] inside_sclass
184
+ # @return [void]
185
+ def walk_for_methods(node, containers, methods, path, inside_sclass: false)
186
+ return unless node.is_a?(Parser::AST::Node)
187
+
188
+ case node.type
189
+ when :class, :module then walk_class_module(node, containers, methods, path)
190
+ when :sclass then walk_sclass(node, containers, methods, path)
191
+ when :def then collect_def(node, containers, methods, path, inside_sclass: inside_sclass)
192
+ when :defs then collect_defs(node, containers, methods, path)
193
+ else walk_children(node, containers, methods, path, inside_sclass: inside_sclass)
194
+ end
195
+ end
196
+
197
+ # @private
198
+ # @param [Parser::AST::Node] node
199
+ # @param [Array<String>] containers
200
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
201
+ # @param [String] path
202
+ # @return [void]
203
+ def walk_class_module(node, containers, methods, path)
204
+ containers.push(const_name(node.children[0]))
205
+ node.children.drop(1).each { |c| walk_for_methods(c, containers, methods, path) }
206
+ containers.pop
207
+ end
208
+
209
+ # @private
210
+ # @param [Parser::AST::Node] node
211
+ # @param [Array<String>] containers
212
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
213
+ # @param [String] path
214
+ # @return [void]
215
+ def walk_sclass(node, containers, methods, path)
216
+ node.children.drop(1).each { |c| walk_for_methods(c, containers, methods, path, inside_sclass: true) }
217
+ end
218
+
219
+ # @private
220
+ # @param [Parser::AST::Node] node
221
+ # @param [Array<String>] containers
222
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
223
+ # @param [String] path
224
+ # @param [Boolean] inside_sclass
225
+ # @return [void]
226
+ def walk_children(node, containers, methods, path, inside_sclass: false)
227
+ node.children.each { |c| walk_for_methods(c, containers, methods, path, inside_sclass: inside_sclass) }
228
+ end
229
+
230
+ # @private
231
+ # @param [Parser::AST::Node] node
232
+ # @param [Array<String>] containers
233
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
234
+ # @param [String] path
235
+ # @param [Boolean] inside_sclass
236
+ # @return [void]
237
+ def collect_def(node, containers, methods, path, inside_sclass: false)
238
+ methods << MethodDef.new(
239
+ name: node.children[0],
240
+ scope: inside_sclass ? :class : :instance,
241
+ container: container_name(containers),
242
+ file: path,
243
+ line: node.loc&.line || 1
244
+ )
245
+ end
246
+
247
+ # @private
248
+ # @param [Parser::AST::Node] node
249
+ # @param [Array<String>] containers
250
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
251
+ # @param [String] path
252
+ # @return [void]
253
+ def collect_defs(node, containers, methods, path)
254
+ methods << MethodDef.new(
255
+ name: node.children[1],
256
+ scope: :class,
257
+ container: container_name(containers),
258
+ file: path,
259
+ line: node.loc&.line || 1
260
+ )
261
+ end
262
+
263
+ # @private
264
+ # @param [Array<String>] containers
265
+ # @return [String?]
266
+ def container_name(containers)
267
+ containers.empty? ? nil : containers.join('::')
268
+ end
269
+
270
+ # @private
271
+ # @param [Parser::AST::Node] node
272
+ # @return [String]
273
+ def const_name(node)
274
+ return node.to_s unless node.is_a?(Parser::AST::Node)
275
+ return node.children[1].to_s if node.type == :const
276
+
277
+ node.children.map { |c| c.is_a?(Parser::AST::Node) ? const_name(c) : c.to_s }.join('::')
278
+ end
279
+
280
+ # @private
281
+ # @param [Hash<Symbol, Object>] options
282
+ # @raise [LoadError]
283
+ # @raise [StandardError]
284
+ # @return [Docscribe::Types::RBS::Provider?] if StandardError
285
+ # @return [nil] if LoadError
286
+ # @return [nil] if StandardError
287
+ def build_provider(options)
288
+ dirs = options[:rbs_collection] ? load_collection_dirs : [] #: Array[String]
289
+ Docscribe::Types::RBS::Provider.new(sig_dirs: options[:sig_dirs], collection_dirs: dirs)
290
+ rescue LoadError
291
+ warn 'Docscribe: rbs gem is not installed. Add `gem "rbs"` to your Gemfile ' \
292
+ 'or run `bundle exec rbs collection install`.'
293
+ nil
294
+ rescue StandardError => e
295
+ warn "Docscribe: Failed to initialize RBS provider: #{e.class}: #{e.message}"
296
+ nil
297
+ end
298
+
299
+ # @private
300
+ # @raise [StandardError]
301
+ # @return [Array<String>] if StandardError
302
+ # @return [Array] if StandardError
303
+ def load_collection_dirs
304
+ dir = Docscribe::Types::RBS::CollectionLoader.resolve
305
+ dir ? [dir] : []
306
+ rescue StandardError => e
307
+ warn "Docscribe: Failed to load RBS collection: #{e.class}: #{e.message}"
308
+ []
309
+ end
310
+
311
+ # @private
312
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
313
+ # @param [Docscribe::Types::RBS::Provider] provider
314
+ # @param [Boolean] verbose
315
+ # @return [Array<Docscribe::CLI::Sigs::MethodDef>]
316
+ def check_sigs(methods, provider, verbose:)
317
+ missing = [] #: Array[MethodDef]
318
+ methods.each do |m|
319
+ sig = lookup_signature(m, provider)
320
+ puts " OK #{format_method(m)} (#{m.file}:#{m.line})" if sig && verbose
321
+ puts " MISS #{format_method(m)} (#{m.file}:#{m.line})" unless sig
322
+ missing << m unless sig
323
+ end
324
+ missing
325
+ end
326
+
327
+ # @private
328
+ # @param [Docscribe::CLI::Sigs::MethodDef] method_def
329
+ # @param [Docscribe::Types::RBS::Provider] provider
330
+ # @return [Object, nil]
331
+ def lookup_signature(method_def, provider)
332
+ container = method_def.container
333
+ return nil unless container
334
+
335
+ provider.signature_for(
336
+ container: container,
337
+ scope: method_def.scope,
338
+ name: method_def.name
339
+ )
340
+ end
341
+
342
+ # @private
343
+ # @param [Docscribe::CLI::Sigs::MethodDef] method_def
344
+ # @return [String]
345
+ def format_method(method_def)
346
+ prefix = method_def.scope == :class ? 'self.' : ''
347
+ container = method_def.container ? "#{method_def.container}#" : ''
348
+ "#{container}#{prefix}#{method_def.name}"
349
+ end
350
+
351
+ # @private
352
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] methods
353
+ # @param [Array<Docscribe::CLI::Sigs::MethodDef>] missing
354
+ # @return [void]
355
+ def report_results(methods, missing)
356
+ puts
357
+ if missing.empty?
358
+ puts "Docscribe: All #{methods.size} methods have RBS signatures"
359
+ else
360
+ puts "Docscribe: #{missing.size}/#{methods.size} methods missing RBS signatures"
361
+ end
362
+ end
363
+ end
364
+ end
365
+ end
366
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+
5
+ require 'docscribe/cli/options'
6
+ require 'docscribe/cli/run'
7
+
8
+ module Docscribe
9
+ module CLI
10
+ # Two-pass update: rebuild docs then re-merge with RBS types.
11
+ #
12
+ # Usage:
13
+ # docscribe update_types [directory]
14
+ #
15
+ # Pass 1: `-AkB --rbs-collection <dir>` — aggressive rebuild, keep descriptions,
16
+ # no boilerplate, using RBS collection signatures.
17
+ # Pass 2: `-aB --rbs-collection <dir>` — safe merge cleanup, no boilerplate,
18
+ # using RBS collection signatures.
19
+ module UpdateTypes
20
+ BANNER = <<~TEXT
21
+ Usage: docscribe update_types [directory]
22
+
23
+ Two-pass type-aware documentation update.
24
+
25
+ Pass 1 (aggressive): docscribe -AkB --rbs-collection <dir>
26
+ rebuild doc blocks, keep descriptions, no boilerplate
27
+
28
+ Pass 2 (safe): docscribe -aB --rbs-collection <dir>
29
+ safe merge cleanup, no boilerplate
30
+
31
+ TEXT
32
+
33
+ class << self
34
+ # @param [Array<String>] argv
35
+ # @return [Integer]
36
+ def run(argv)
37
+ options = parse_options(argv)
38
+ dir = options[:dir]
39
+
40
+ announce_start
41
+
42
+ exit1 = run_first_pass(dir)
43
+ return exit1 unless exit1.zero?
44
+
45
+ exit2 = run_second_pass(dir)
46
+ return exit2 unless exit2.zero?
47
+
48
+ announce_complete
49
+ 0
50
+ end
51
+
52
+ private
53
+
54
+ # @private
55
+ # @param [Array<String>] argv
56
+ # @return [Hash<Symbol, Object>]
57
+ def parse_options(argv)
58
+ options = { dir: '.' }
59
+ OptionParser.new(BANNER) do |opts|
60
+ opts.on('-h', '--help', 'Show this help') { puts opts or exit 0 }
61
+ opts.parse!(argv)
62
+ end
63
+ options[:dir] = argv.first if argv.any?
64
+ options
65
+ end
66
+
67
+ # @private
68
+ # @return [void]
69
+ def announce_start
70
+ puts 'Docscribe: Running type-aware documentation update...'
71
+ puts
72
+ end
73
+
74
+ # @private
75
+ # @param [String] dir
76
+ # @return [Integer]
77
+ def run_first_pass(dir)
78
+ puts 'Pass 1: Aggressive rebuild with RBS collection...'
79
+ argv1 = ['-AkB', '--rbs-collection', dir]
80
+ options1 = Docscribe::CLI::Options.parse!(argv1)
81
+ Docscribe::CLI::Run.run(options: options1, argv: [dir])
82
+ end
83
+
84
+ # @private
85
+ # @param [String] dir
86
+ # @return [Integer]
87
+ def run_second_pass(dir)
88
+ puts 'Pass 2: Safe merge with RBS collection...'
89
+ argv2 = ['-aB', '--rbs-collection', dir]
90
+ options2 = Docscribe::CLI::Options.parse!(argv2)
91
+ Docscribe::CLI::Run.run(options: options2, argv: [dir])
92
+ end
93
+
94
+ # @private
95
+ # @return [void]
96
+ def announce_complete
97
+ puts
98
+ puts 'Docscribe: Type-aware documentation update complete.'
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
data/lib/docscribe/cli.rb CHANGED
@@ -4,8 +4,13 @@ require 'docscribe/cli/init'
4
4
  require 'docscribe/cli/generate'
5
5
  require 'docscribe/cli/options'
6
6
  require 'docscribe/cli/run'
7
+ require 'docscribe/cli/sigs'
8
+ require 'docscribe/cli/rbs_gen'
9
+ require 'docscribe/cli/update_types'
10
+ require 'docscribe/cli/check_for_comments'
7
11
 
8
12
  module Docscribe
13
+ # CLI entry point and command dispatch.
9
14
  module CLI
10
15
  class << self
11
16
  # Main CLI entry point.
@@ -19,19 +24,40 @@ module Docscribe
19
24
  # @return [Integer] process exit code
20
25
  def run(argv)
21
26
  argv = argv.dup
22
-
23
- case argv.first
24
- when 'init'
25
- argv.shift
26
- return Docscribe::CLI::Init.run(argv)
27
- when 'generate'
28
- argv.shift
29
- return Docscribe::CLI::Generate.run(argv)
30
- end
27
+ return dispatch_subcommand(argv) if subcommand?(argv.first)
31
28
 
32
29
  options = Docscribe::CLI::Options.parse!(argv)
33
30
  Docscribe::CLI::Run.run(options: options, argv: argv)
34
31
  end
32
+
33
+ private
34
+
35
+ # Subcommand
36
+ #
37
+ # @private
38
+ # @param [String?] cmd potential subcommand name
39
+ # @return [Boolean]
40
+ def subcommand?(cmd)
41
+ %w[init generate sigs rbs update_types check_for_comments].include?(cmd)
42
+ end
43
+
44
+ # Dispatch subcommand
45
+ #
46
+ # @private
47
+ # @param [Array<String>] argv raw command-line arguments
48
+ # @return [Integer]
49
+ def dispatch_subcommand(argv)
50
+ cmd = argv.shift
51
+ case cmd
52
+ when 'init' then Docscribe::CLI::Init.run(argv)
53
+ when 'generate' then Docscribe::CLI::Generate.run(argv)
54
+ when 'sigs' then Docscribe::CLI::Sigs.run(argv)
55
+ when 'rbs' then Docscribe::CLI::RbsGen.run(argv)
56
+ when 'update_types' then Docscribe::CLI::UpdateTypes.run(argv)
57
+ when 'check_for_comments' then Docscribe::CLI::CheckForComments.run(argv)
58
+ else 0
59
+ end
60
+ end
35
61
  end
36
62
  end
37
63
  end
@@ -33,14 +33,14 @@ module Docscribe
33
33
  },
34
34
  'methods' => {
35
35
  'instance' => {
36
- 'public' => {},
37
- 'protected' => {},
38
- 'private' => {}
36
+ 'public' => {}, #: Hash[String, untyped]
37
+ 'protected' => {}, #: Hash[String, untyped]
38
+ 'private' => {} #: Hash[String, untyped]
39
39
  },
40
40
  'class' => {
41
- 'public' => {},
42
- 'protected' => {},
43
- 'private' => {}
41
+ 'public' => {}, #: Hash[String, untyped]
42
+ 'protected' => {}, #: Hash[String, untyped]
43
+ 'private' => {} #: Hash[String, untyped]
44
44
  }
45
45
  },
46
46
  'inference' => {
@@ -51,10 +51,10 @@ module Docscribe
51
51
  'filter' => {
52
52
  'visibilities' => %w[public protected private],
53
53
  'scopes' => %w[instance class],
54
- 'include' => [],
55
- 'exclude' => [],
54
+ 'include' => [], #: Array[String]
55
+ 'exclude' => [], #: Array[String]
56
56
  'files' => {
57
- 'include' => [],
57
+ 'include' => [], #: Array[String]
58
58
  'exclude' => ['spec']
59
59
  }
60
60
  },
@@ -62,16 +62,20 @@ module Docscribe
62
62
  'enabled' => false,
63
63
  'collection' => false,
64
64
  'sig_dirs' => ['sig'],
65
- 'collection_dirs' => [],
66
- 'collapse_generics' => false
65
+ 'collection_dirs' => [], #: Array[String]
66
+ 'collapse_generics' => false,
67
+ 'warn_missing_collection' => true,
68
+ 'collapse_object_generics' => false
67
69
  },
68
70
  'sorbet' => {
69
71
  'enabled' => false,
70
72
  'rbi_dirs' => ['sorbet/rbi', 'rbi'],
71
73
  'collapse_generics' => false
72
74
  },
75
+ 'keep_descriptions' => false,
76
+ 'skip_anonymous_block_params' => false,
73
77
  'plugins' => {
74
- 'require' => []
78
+ 'require' => [] #: Array[String]
75
79
  }
76
80
  }.freeze
77
81
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Docscribe
4
+ # Emit-related configuration (headers, visibility tags, etc.).
4
5
  class Config
5
6
  # Whether to emit method header lines such as:
6
7
  # # +MyClass#foo+ -> Integer
@@ -138,5 +139,22 @@ module Docscribe
138
139
  def include_param_documentation?
139
140
  fetch_bool(%w[emit include_param_documentation], true)
140
141
  end
142
+
143
+ # Whether to preserve existing @param/@return descriptions in aggressive mode.
144
+ #
145
+ # @return [Boolean]
146
+ def keep_descriptions?
147
+ fetch_bool(%w[keep_descriptions], false)
148
+ end
149
+
150
+ # Whether to skip @param generation for anonymous block arguments (&).
151
+ #
152
+ # Ruby 3.2+ allows `def foo(&)`. When enabled, no @param is generated
153
+ # for anonymous block parameters since they have no name to reference.
154
+ #
155
+ # @return [Boolean]
156
+ def skip_anonymous_block_params?
157
+ fetch_bool(%w[skip_anonymous_block_params], false)
158
+ end
141
159
  end
142
160
  end