docscribe 1.1.0 → 1.2.1
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 +4 -4
- data/README.md +662 -187
- data/exe/docscribe +2 -126
- data/lib/docscribe/cli/config_builder.rb +62 -0
- data/lib/docscribe/cli/init.rb +58 -0
- data/lib/docscribe/cli/options.rb +204 -0
- data/lib/docscribe/cli/run.rb +415 -0
- data/lib/docscribe/cli.rb +31 -0
- data/lib/docscribe/config/defaults.rb +71 -0
- data/lib/docscribe/config/emit.rb +142 -0
- data/lib/docscribe/config/filtering.rb +160 -0
- data/lib/docscribe/config/loader.rb +59 -0
- data/lib/docscribe/config/rbs.rb +51 -0
- data/lib/docscribe/config/sorbet.rb +87 -0
- data/lib/docscribe/config/sorting.rb +23 -0
- data/lib/docscribe/config/template.rb +184 -0
- data/lib/docscribe/config/utils.rb +102 -0
- data/lib/docscribe/config.rb +20 -230
- data/lib/docscribe/infer/ast_walk.rb +28 -0
- data/lib/docscribe/infer/constants.rb +11 -0
- data/lib/docscribe/infer/literals.rb +55 -0
- data/lib/docscribe/infer/names.rb +43 -0
- data/lib/docscribe/infer/params.rb +62 -0
- data/lib/docscribe/infer/raises.rb +68 -0
- data/lib/docscribe/infer/returns.rb +171 -0
- data/lib/docscribe/infer.rb +104 -258
- data/lib/docscribe/inline_rewriter/collector.rb +845 -0
- data/lib/docscribe/inline_rewriter/doc_block.rb +383 -0
- data/lib/docscribe/inline_rewriter/doc_builder.rb +607 -0
- data/lib/docscribe/inline_rewriter/source_helpers.rb +228 -0
- data/lib/docscribe/inline_rewriter/tag_sorter.rb +244 -0
- data/lib/docscribe/inline_rewriter.rb +599 -428
- data/lib/docscribe/parsing.rb +55 -44
- data/lib/docscribe/types/provider_chain.rb +37 -0
- data/lib/docscribe/types/rbs/provider.rb +213 -0
- data/lib/docscribe/types/rbs/type_formatter.rb +132 -0
- data/lib/docscribe/types/signature.rb +65 -0
- data/lib/docscribe/types/sorbet/base_provider.rb +217 -0
- data/lib/docscribe/types/sorbet/rbi_provider.rb +35 -0
- data/lib/docscribe/types/sorbet/source_provider.rb +25 -0
- data/lib/docscribe/version.rb +1 -1
- metadata +37 -3
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'pathname'
|
|
4
|
+
|
|
5
|
+
require 'docscribe/cli/config_builder'
|
|
6
|
+
require 'docscribe/inline_rewriter'
|
|
7
|
+
|
|
8
|
+
module Docscribe
|
|
9
|
+
module CLI
|
|
10
|
+
# Execute Docscribe from parsed CLI options.
|
|
11
|
+
#
|
|
12
|
+
# This module handles:
|
|
13
|
+
# - config loading and CLI overrides
|
|
14
|
+
# - stdin mode
|
|
15
|
+
# - file expansion / filtering
|
|
16
|
+
# - inspect vs write behavior
|
|
17
|
+
# - process exit status
|
|
18
|
+
module Run
|
|
19
|
+
class << self
|
|
20
|
+
# Run Docscribe for files or STDIN using the selected mode and strategy.
|
|
21
|
+
#
|
|
22
|
+
# Modes:
|
|
23
|
+
# - :check => inspect what the selected strategy would change
|
|
24
|
+
# - :write => apply the selected strategy in place
|
|
25
|
+
# - :stdin => rewrite STDIN and print to STDOUT
|
|
26
|
+
#
|
|
27
|
+
# Strategies:
|
|
28
|
+
# - :safe => merge/add/normalize non-destructively
|
|
29
|
+
# - :aggressive => rebuild existing doc blocks
|
|
30
|
+
#
|
|
31
|
+
# @param [Hash] options parsed CLI options
|
|
32
|
+
# @param [Array<String>] argv remaining path arguments
|
|
33
|
+
# @return [Integer] process exit code
|
|
34
|
+
def run(options:, argv:)
|
|
35
|
+
conf = Docscribe::Config.load(options[:config])
|
|
36
|
+
conf = Docscribe::CLI::ConfigBuilder.build(conf, options)
|
|
37
|
+
|
|
38
|
+
return run_stdin(options: options, conf: conf) if options[:mode] == :stdin
|
|
39
|
+
|
|
40
|
+
paths = expand_paths(argv)
|
|
41
|
+
paths = paths.select { |p| conf.process_file?(p) }
|
|
42
|
+
|
|
43
|
+
if paths.empty?
|
|
44
|
+
warn 'No files found. Pass files or directories (e.g. `docscribe lib`).'
|
|
45
|
+
return 1
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
run_files(options: options, conf: conf, paths: paths)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Rewrite code from STDIN using the selected strategy and print the
|
|
52
|
+
# result.
|
|
53
|
+
#
|
|
54
|
+
# @param [Hash] options parsed CLI options
|
|
55
|
+
# @param [Docscribe::Config] conf effective config
|
|
56
|
+
# @raise [StandardError]
|
|
57
|
+
# @return [Integer] process exit code
|
|
58
|
+
def run_stdin(options:, conf:)
|
|
59
|
+
code = $stdin.read
|
|
60
|
+
result = Docscribe::InlineRewriter.rewrite_with_report(
|
|
61
|
+
code,
|
|
62
|
+
strategy: options[:strategy],
|
|
63
|
+
config: conf,
|
|
64
|
+
file: '(stdin)'
|
|
65
|
+
)
|
|
66
|
+
puts result[:output]
|
|
67
|
+
0
|
|
68
|
+
rescue StandardError => e
|
|
69
|
+
warn "Docscribe: Error processing stdin: #{e.class}: #{e.message}"
|
|
70
|
+
1
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Expand CLI path arguments into a sorted list of Ruby files.
|
|
74
|
+
#
|
|
75
|
+
# Directories are expanded recursively to `**/*.rb`.
|
|
76
|
+
# If no arguments are provided, the current directory is used.
|
|
77
|
+
#
|
|
78
|
+
# @param [Array<String>] args file and/or directory arguments
|
|
79
|
+
# @return [Array<String>] unique sorted Ruby file paths
|
|
80
|
+
def expand_paths(args)
|
|
81
|
+
files = []
|
|
82
|
+
args = ['.'] if args.empty?
|
|
83
|
+
|
|
84
|
+
args.each do |path|
|
|
85
|
+
if File.directory?(path)
|
|
86
|
+
files.concat(Dir.glob(File.join(path, '**', '*.rb')))
|
|
87
|
+
elsif File.file?(path)
|
|
88
|
+
files << path
|
|
89
|
+
else
|
|
90
|
+
warn "Skipping missing path: #{path}"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
files.uniq.sort
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Process file paths in inspect or write mode.
|
|
98
|
+
#
|
|
99
|
+
# In inspect mode:
|
|
100
|
+
# - prints progress/status
|
|
101
|
+
# - exits non-zero if any file would change or if any errors occurred
|
|
102
|
+
#
|
|
103
|
+
# In write mode:
|
|
104
|
+
# - rewrites changed files in place
|
|
105
|
+
# - exits non-zero only if errors occurred
|
|
106
|
+
#
|
|
107
|
+
# @param [Hash] options parsed CLI options
|
|
108
|
+
# @param [Docscribe::Config] conf effective config
|
|
109
|
+
# @param [Array<String>] paths Ruby file paths to process
|
|
110
|
+
# @return [Integer] process exit code
|
|
111
|
+
def run_files(options:, conf:, paths:)
|
|
112
|
+
$stdout.sync = true
|
|
113
|
+
|
|
114
|
+
state = initial_run_state
|
|
115
|
+
pwd = Pathname.pwd
|
|
116
|
+
|
|
117
|
+
paths.each do |path|
|
|
118
|
+
process_one_file(path, options: options, conf: conf, pwd: pwd, state: state)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
if options[:mode] == :check
|
|
122
|
+
print_check_summary(state: state, options: options)
|
|
123
|
+
elsif options[:mode] == :write
|
|
124
|
+
print_write_summary(state: state)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
return 1 if state[:had_errors]
|
|
128
|
+
return 1 if options[:mode] == :check && state[:changed]
|
|
129
|
+
|
|
130
|
+
0
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
private
|
|
134
|
+
|
|
135
|
+
# Method documentation.
|
|
136
|
+
#
|
|
137
|
+
# @private
|
|
138
|
+
# @return [Hash]
|
|
139
|
+
def initial_run_state
|
|
140
|
+
{
|
|
141
|
+
changed: false,
|
|
142
|
+
had_errors: false,
|
|
143
|
+
checked_ok: 0,
|
|
144
|
+
checked_fail: 0,
|
|
145
|
+
corrected: 0,
|
|
146
|
+
fail_paths: [],
|
|
147
|
+
fail_changes: {},
|
|
148
|
+
error_paths: [],
|
|
149
|
+
error_messages: {}
|
|
150
|
+
}
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Method documentation.
|
|
154
|
+
#
|
|
155
|
+
# @private
|
|
156
|
+
# @param [Object] path Param documentation.
|
|
157
|
+
# @param [Hash] options Param documentation.
|
|
158
|
+
# @param [Object] conf Param documentation.
|
|
159
|
+
# @param [Object] pwd Param documentation.
|
|
160
|
+
# @param [Object] state Param documentation.
|
|
161
|
+
# @return [Object]
|
|
162
|
+
def process_one_file(path, options:, conf:, pwd:, state:)
|
|
163
|
+
display_path = display_path_for(path, pwd: pwd)
|
|
164
|
+
|
|
165
|
+
src = read_source_for_path(path, display_path: display_path, options: options, state: state)
|
|
166
|
+
return unless src
|
|
167
|
+
|
|
168
|
+
result = rewrite_result_for_path(path, src: src, conf: conf, display_path: display_path, options: options,
|
|
169
|
+
state: state)
|
|
170
|
+
return unless result
|
|
171
|
+
|
|
172
|
+
out = result[:output]
|
|
173
|
+
file_changes = result[:changes] || []
|
|
174
|
+
|
|
175
|
+
if options[:mode] == :check
|
|
176
|
+
handle_check_result(
|
|
177
|
+
path,
|
|
178
|
+
src: src,
|
|
179
|
+
out: out,
|
|
180
|
+
file_changes: file_changes,
|
|
181
|
+
display_path: display_path,
|
|
182
|
+
options: options,
|
|
183
|
+
state: state
|
|
184
|
+
)
|
|
185
|
+
elsif options[:mode] == :write
|
|
186
|
+
handle_write_result(
|
|
187
|
+
path,
|
|
188
|
+
src: src,
|
|
189
|
+
out: out,
|
|
190
|
+
file_changes: file_changes,
|
|
191
|
+
display_path: display_path,
|
|
192
|
+
options: options,
|
|
193
|
+
state: state
|
|
194
|
+
)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Prefer a relative display path when the file is under the current working directory.
|
|
199
|
+
#
|
|
200
|
+
# Falls back to basename for files outside the project root or when relative path
|
|
201
|
+
# computation fails.
|
|
202
|
+
#
|
|
203
|
+
# @private
|
|
204
|
+
# @param [String] path file path to display
|
|
205
|
+
# @param [Pathname] pwd current working directory
|
|
206
|
+
# @raise [StandardError]
|
|
207
|
+
# @return [String] path shown in CLI output
|
|
208
|
+
def display_path_for(path, pwd:)
|
|
209
|
+
abs = Pathname.new(path).expand_path
|
|
210
|
+
|
|
211
|
+
pwd_str = pwd.to_s
|
|
212
|
+
abs_str = abs.to_s
|
|
213
|
+
return abs.relative_path_from(pwd).to_s if abs_str.start_with?(pwd_str + File::SEPARATOR)
|
|
214
|
+
|
|
215
|
+
File.basename(abs_str)
|
|
216
|
+
rescue StandardError
|
|
217
|
+
File.basename(path.to_s)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Method documentation.
|
|
221
|
+
#
|
|
222
|
+
# @private
|
|
223
|
+
# @param [Object] path Param documentation.
|
|
224
|
+
# @param [Object] display_path Param documentation.
|
|
225
|
+
# @param [Hash] options Param documentation.
|
|
226
|
+
# @param [Object] state Param documentation.
|
|
227
|
+
# @raise [StandardError]
|
|
228
|
+
# @return [Object]
|
|
229
|
+
# @return [nil] if StandardError
|
|
230
|
+
def read_source_for_path(path, display_path:, options:, state:)
|
|
231
|
+
File.read(path)
|
|
232
|
+
rescue StandardError => e
|
|
233
|
+
state[:had_errors] = true
|
|
234
|
+
state[:error_paths] << path
|
|
235
|
+
state[:error_messages][path] = "#{e.class}: #{e.message}"
|
|
236
|
+
options[:verbose] ? warn("ERR #{display_path}: #{state[:error_messages][path]}") : print('E')
|
|
237
|
+
nil
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Method documentation.
|
|
241
|
+
#
|
|
242
|
+
# @private
|
|
243
|
+
# @param [Object] path Param documentation.
|
|
244
|
+
# @param [Object] src Param documentation.
|
|
245
|
+
# @param [Object] conf Param documentation.
|
|
246
|
+
# @param [Object] display_path Param documentation.
|
|
247
|
+
# @param [Hash] options Param documentation.
|
|
248
|
+
# @param [Object] state Param documentation.
|
|
249
|
+
# @raise [StandardError]
|
|
250
|
+
# @return [Object]
|
|
251
|
+
# @return [nil] if StandardError
|
|
252
|
+
def rewrite_result_for_path(path, src:, conf:, display_path:, options:, state:)
|
|
253
|
+
Docscribe::InlineRewriter.rewrite_with_report(
|
|
254
|
+
src,
|
|
255
|
+
strategy: options[:strategy],
|
|
256
|
+
config: conf,
|
|
257
|
+
file: path
|
|
258
|
+
)
|
|
259
|
+
rescue StandardError => e
|
|
260
|
+
state[:had_errors] = true
|
|
261
|
+
state[:error_paths] << path
|
|
262
|
+
state[:error_messages][path] = "#{e.class}: #{e.message}"
|
|
263
|
+
options[:verbose] ? warn("ERR #{display_path}: #{state[:error_messages][path]}") : print('E')
|
|
264
|
+
nil
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# Method documentation.
|
|
268
|
+
#
|
|
269
|
+
# @private
|
|
270
|
+
# @param [Object] path Param documentation.
|
|
271
|
+
# @param [Object] src Param documentation.
|
|
272
|
+
# @param [Object] out Param documentation.
|
|
273
|
+
# @param [Object] file_changes Param documentation.
|
|
274
|
+
# @param [Object] display_path Param documentation.
|
|
275
|
+
# @param [Hash] options Param documentation.
|
|
276
|
+
# @param [Object] state Param documentation.
|
|
277
|
+
# @return [Object]
|
|
278
|
+
def handle_check_result(path, src:, out:, file_changes:, display_path:, options:, state:)
|
|
279
|
+
if out == src
|
|
280
|
+
options[:verbose] ? puts("OK #{display_path}") : print('.')
|
|
281
|
+
state[:checked_ok] += 1
|
|
282
|
+
return
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
if options[:verbose]
|
|
286
|
+
puts("FAIL #{display_path}")
|
|
287
|
+
if options[:explain]
|
|
288
|
+
file_changes.each do |change|
|
|
289
|
+
puts(" - #{format_change_reason(change)}")
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
else
|
|
293
|
+
print('F')
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
state[:checked_fail] += 1
|
|
297
|
+
state[:changed] = true
|
|
298
|
+
state[:fail_paths] << path
|
|
299
|
+
state[:fail_changes][path] = file_changes
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# Method documentation.
|
|
303
|
+
#
|
|
304
|
+
# @private
|
|
305
|
+
# @param [Object] path Param documentation.
|
|
306
|
+
# @param [Object] src Param documentation.
|
|
307
|
+
# @param [Object] out Param documentation.
|
|
308
|
+
# @param [Object] file_changes Param documentation.
|
|
309
|
+
# @param [Object] display_path Param documentation.
|
|
310
|
+
# @param [Hash] options Param documentation.
|
|
311
|
+
# @param [Object] state Param documentation.
|
|
312
|
+
# @raise [StandardError]
|
|
313
|
+
# @return [Object]
|
|
314
|
+
# @return [Object] if StandardError
|
|
315
|
+
def handle_write_result(path, src:, out:, file_changes:, display_path:, options:, state:)
|
|
316
|
+
if out == src
|
|
317
|
+
options[:verbose] ? puts("OK #{display_path}") : print('.')
|
|
318
|
+
return
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
File.write(path, out)
|
|
322
|
+
|
|
323
|
+
if options[:verbose]
|
|
324
|
+
puts("CHANGED #{display_path}")
|
|
325
|
+
if options[:explain]
|
|
326
|
+
file_changes.each do |change|
|
|
327
|
+
puts(" - #{format_change_reason(change)}")
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
else
|
|
331
|
+
print('C')
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
state[:corrected] += 1
|
|
335
|
+
rescue StandardError => e
|
|
336
|
+
state[:had_errors] = true
|
|
337
|
+
state[:error_paths] << path
|
|
338
|
+
state[:error_messages][path] = "#{e.class}: #{e.message}"
|
|
339
|
+
options[:verbose] ? warn("ERR #{display_path}: #{state[:error_messages][path]}") : print('E')
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Method documentation.
|
|
343
|
+
#
|
|
344
|
+
# @private
|
|
345
|
+
# @param [Object] state Param documentation.
|
|
346
|
+
# @param [Hash] options Param documentation.
|
|
347
|
+
# @return [Object]
|
|
348
|
+
def print_check_summary(state:, options:)
|
|
349
|
+
puts
|
|
350
|
+
|
|
351
|
+
checked_error = state[:error_paths].size
|
|
352
|
+
|
|
353
|
+
if state[:checked_fail].zero? && checked_error.zero?
|
|
354
|
+
puts "Docscribe: OK (#{state[:checked_ok]} files checked)"
|
|
355
|
+
return
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
puts "Docscribe: FAILED (#{state[:checked_fail]} files need updates, #{checked_error} errors, #{state[:checked_ok]} ok)"
|
|
359
|
+
|
|
360
|
+
state[:fail_paths].each do |p|
|
|
361
|
+
warn "Would update docs: #{p}"
|
|
362
|
+
next unless options[:explain] && !options[:verbose]
|
|
363
|
+
|
|
364
|
+
Array(state[:fail_changes][p]).each do |change|
|
|
365
|
+
warn " - #{format_change_reason(change)}"
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
state[:error_paths].each do |p|
|
|
370
|
+
warn "Error processing: #{p}"
|
|
371
|
+
warn " #{state[:error_messages][p]}" if state[:error_messages][p]
|
|
372
|
+
end
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# Format a structured change record into human-readable CLI output.
|
|
376
|
+
#
|
|
377
|
+
# @private
|
|
378
|
+
# @param [Hash] change structured change produced by the inline rewriter
|
|
379
|
+
# @return [String] human-readable explanation line
|
|
380
|
+
def format_change_reason(change)
|
|
381
|
+
line = change[:line] ? " at line #{change[:line]}" : ''
|
|
382
|
+
method = change[:method] ? " for #{change[:method]}" : ''
|
|
383
|
+
|
|
384
|
+
case change[:type]
|
|
385
|
+
when :unsorted_tags
|
|
386
|
+
"unsorted tags#{line}"
|
|
387
|
+
when :missing_param, :missing_return, :missing_raise, :missing_visibility, :missing_module_function_note,
|
|
388
|
+
:insert_full_doc_block
|
|
389
|
+
"#{change[:message]}#{method}#{line}"
|
|
390
|
+
else
|
|
391
|
+
"#{change[:message] || change[:type].to_s.tr('_', ' ')}#{method}#{line}"
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
# Method documentation.
|
|
396
|
+
#
|
|
397
|
+
# @private
|
|
398
|
+
# @param [Object] state Param documentation.
|
|
399
|
+
# @return [Object]
|
|
400
|
+
def print_write_summary(state:)
|
|
401
|
+
puts
|
|
402
|
+
puts "Docscribe: updated #{state[:corrected]} file(s)" if state[:corrected].positive?
|
|
403
|
+
|
|
404
|
+
return unless state[:had_errors]
|
|
405
|
+
|
|
406
|
+
warn "Docscribe: #{state[:error_paths].size} file(s) had errors"
|
|
407
|
+
state[:error_paths].each do |p|
|
|
408
|
+
warn "Error processing: #{p}"
|
|
409
|
+
warn " #{state[:error_messages][p]}" if state[:error_messages][p]
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'docscribe/cli/init'
|
|
4
|
+
require 'docscribe/cli/options'
|
|
5
|
+
require 'docscribe/cli/run'
|
|
6
|
+
|
|
7
|
+
module Docscribe
|
|
8
|
+
module CLI
|
|
9
|
+
class << self
|
|
10
|
+
# Main CLI entry point.
|
|
11
|
+
#
|
|
12
|
+
# Dispatches:
|
|
13
|
+
# - `docscribe init ...` to the config-template generator
|
|
14
|
+
# - all other commands to the main option parser and runner
|
|
15
|
+
#
|
|
16
|
+
# @param [Array<String>] argv raw command-line arguments
|
|
17
|
+
# @return [Integer] process exit code
|
|
18
|
+
def run(argv)
|
|
19
|
+
argv = argv.dup
|
|
20
|
+
|
|
21
|
+
if argv.first == 'init'
|
|
22
|
+
argv.shift
|
|
23
|
+
return Docscribe::CLI::Init.run(argv)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
options = Docscribe::CLI::Options.parse!(argv)
|
|
27
|
+
Docscribe::CLI::Run.run(options: options, argv: argv)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Docscribe
|
|
4
|
+
class Config
|
|
5
|
+
# Default configuration values used when no `docscribe.yml` is present or
|
|
6
|
+
# when specific keys are missing from user config.
|
|
7
|
+
#
|
|
8
|
+
# These defaults define:
|
|
9
|
+
# - which documentation tags are emitted
|
|
10
|
+
# - default generated text
|
|
11
|
+
# - type inference behavior
|
|
12
|
+
# - method / file filtering
|
|
13
|
+
# - optional RBS integration
|
|
14
|
+
# - optional Sorbet integration
|
|
15
|
+
DEFAULT = {
|
|
16
|
+
'emit' => {
|
|
17
|
+
'header' => true,
|
|
18
|
+
'param_tags' => true,
|
|
19
|
+
'return_tag' => true,
|
|
20
|
+
'visibility_tags' => true,
|
|
21
|
+
'raise_tags' => true,
|
|
22
|
+
'rescue_conditional_returns' => true,
|
|
23
|
+
'attributes' => false
|
|
24
|
+
},
|
|
25
|
+
'doc' => {
|
|
26
|
+
'default_message' => 'Method documentation.',
|
|
27
|
+
'param_tag_style' => 'type_name',
|
|
28
|
+
'param_documentation' => 'Param documentation.',
|
|
29
|
+
'sort_tags' => true,
|
|
30
|
+
'tag_order' => %w[todo note api private protected param option yieldparam raise return]
|
|
31
|
+
},
|
|
32
|
+
'methods' => {
|
|
33
|
+
'instance' => {
|
|
34
|
+
'public' => {},
|
|
35
|
+
'protected' => {},
|
|
36
|
+
'private' => {}
|
|
37
|
+
},
|
|
38
|
+
'class' => {
|
|
39
|
+
'public' => {},
|
|
40
|
+
'protected' => {},
|
|
41
|
+
'private' => {}
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
'inference' => {
|
|
45
|
+
'fallback_type' => 'Object',
|
|
46
|
+
'nil_as_optional' => true,
|
|
47
|
+
'treat_options_keyword_as_hash' => true
|
|
48
|
+
},
|
|
49
|
+
'filter' => {
|
|
50
|
+
'visibilities' => %w[public protected private],
|
|
51
|
+
'scopes' => %w[instance class],
|
|
52
|
+
'include' => [],
|
|
53
|
+
'exclude' => [],
|
|
54
|
+
'files' => {
|
|
55
|
+
'include' => [],
|
|
56
|
+
'exclude' => []
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
'rbs' => {
|
|
60
|
+
'enabled' => false,
|
|
61
|
+
'sig_dirs' => ['sig'],
|
|
62
|
+
'collapse_generics' => false
|
|
63
|
+
},
|
|
64
|
+
'sorbet' => {
|
|
65
|
+
'enabled' => false,
|
|
66
|
+
'rbi_dirs' => ['sorbet/rbi', 'rbi'],
|
|
67
|
+
'collapse_generics' => false
|
|
68
|
+
}
|
|
69
|
+
}.freeze
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Docscribe
|
|
4
|
+
class Config
|
|
5
|
+
# Whether to emit method header lines such as:
|
|
6
|
+
# # +MyClass#foo+ -> Integer
|
|
7
|
+
#
|
|
8
|
+
# @return [Boolean]
|
|
9
|
+
def emit_header?
|
|
10
|
+
fetch_bool(%w[emit header], true)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Whether to emit `@param` tags.
|
|
14
|
+
#
|
|
15
|
+
# @return [Boolean]
|
|
16
|
+
def emit_param_tags?
|
|
17
|
+
fetch_bool(%w[emit param_tags], true)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Whether to emit visibility tags such as `@private` and `@protected`.
|
|
21
|
+
#
|
|
22
|
+
# @return [Boolean]
|
|
23
|
+
def emit_visibility_tags?
|
|
24
|
+
fetch_bool(%w[emit visibility_tags], true)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Whether to emit inferred `@raise` tags.
|
|
28
|
+
#
|
|
29
|
+
# @return [Boolean]
|
|
30
|
+
def emit_raise_tags?
|
|
31
|
+
fetch_bool(%w[emit raise_tags], true)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Whether to emit conditional rescue-return tags like:
|
|
35
|
+
# # @return [String] if FooError
|
|
36
|
+
#
|
|
37
|
+
# @return [Boolean]
|
|
38
|
+
def emit_rescue_conditional_returns?
|
|
39
|
+
fetch_bool(%w[emit rescue_conditional_returns], true)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Whether to emit YARD `@!attribute` docs for `attr_*` macros.
|
|
43
|
+
#
|
|
44
|
+
# @return [Boolean]
|
|
45
|
+
def emit_attributes?
|
|
46
|
+
fetch_bool(%w[emit attributes], false)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Whether to emit the `@return` tag for a method, taking per-scope and
|
|
50
|
+
# per-visibility overrides into account.
|
|
51
|
+
#
|
|
52
|
+
# @param [Symbol] scope :instance or :class
|
|
53
|
+
# @param [Symbol] visibility :public, :protected, or :private
|
|
54
|
+
# @return [Boolean]
|
|
55
|
+
def emit_return_tag?(scope, visibility)
|
|
56
|
+
method_override_bool(
|
|
57
|
+
scope,
|
|
58
|
+
visibility,
|
|
59
|
+
'return_tag',
|
|
60
|
+
default: fetch_bool(%w[emit return_tag], true)
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Default text inserted into generated doc blocks, taking per-scope and
|
|
65
|
+
# per-visibility overrides into account.
|
|
66
|
+
#
|
|
67
|
+
# @param [Symbol] scope :instance or :class
|
|
68
|
+
# @param [Symbol] visibility :public, :protected, or :private
|
|
69
|
+
# @return [String]
|
|
70
|
+
def default_message(scope, visibility)
|
|
71
|
+
method_override_str(
|
|
72
|
+
scope,
|
|
73
|
+
visibility,
|
|
74
|
+
'default_message',
|
|
75
|
+
default: raw.dig('doc', 'default_message') ||
|
|
76
|
+
DEFAULT.dig('doc', 'default_message') ||
|
|
77
|
+
'Method documentation.'
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Fallback type used when inference cannot determine a more specific type.
|
|
82
|
+
#
|
|
83
|
+
# @return [String]
|
|
84
|
+
def fallback_type
|
|
85
|
+
raw.dig('inference', 'fallback_type') ||
|
|
86
|
+
DEFAULT.dig('inference', 'fallback_type') ||
|
|
87
|
+
'Object'
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Whether unions involving nil should be rendered as optional types.
|
|
91
|
+
#
|
|
92
|
+
# For example, `String, nil` may become `String?` depending on formatter
|
|
93
|
+
# behavior.
|
|
94
|
+
#
|
|
95
|
+
# @return [Boolean]
|
|
96
|
+
def nil_as_optional?
|
|
97
|
+
fetch_bool(%w[inference nil_as_optional], true)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Whether keyword arguments named `options` / `options:` should be treated
|
|
101
|
+
# specially as Hash values during inference.
|
|
102
|
+
#
|
|
103
|
+
# @return [Boolean]
|
|
104
|
+
def treat_options_keyword_as_hash?
|
|
105
|
+
fetch_bool(%w[inference treat_options_keyword_as_hash], true)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Param tag syntax style.
|
|
109
|
+
#
|
|
110
|
+
# Supported values:
|
|
111
|
+
# - `"type_name"` => `@param [String] name`
|
|
112
|
+
# - `"name_type"` => `@param name [String]`
|
|
113
|
+
#
|
|
114
|
+
# @return [String]
|
|
115
|
+
def param_tag_style
|
|
116
|
+
raw.dig('doc', 'param_tag_style') || DEFAULT.dig('doc', 'param_tag_style')
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Default generated parameter description text.
|
|
120
|
+
#
|
|
121
|
+
# @return [String]
|
|
122
|
+
def param_documentation
|
|
123
|
+
raw.dig('doc', 'param_documentation') || DEFAULT.dig('doc', 'param_documentation')
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Whether to include the default placeholder line:
|
|
127
|
+
# # Method documentation.
|
|
128
|
+
#
|
|
129
|
+
# @return [Boolean]
|
|
130
|
+
def include_default_message?
|
|
131
|
+
fetch_bool(%w[emit include_default_message], true)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Whether to append placeholder text to generated @param tags:
|
|
135
|
+
# # @param [String] name Param documentation.
|
|
136
|
+
#
|
|
137
|
+
# @return [Boolean]
|
|
138
|
+
def include_param_documentation?
|
|
139
|
+
fetch_bool(%w[emit include_param_documentation], true)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|