docscribe 1.4.2 → 1.5.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 +601 -139
- data/exe/docscribe-client +105 -0
- data/lib/docscribe/cli/check_for_comments.rb +183 -0
- data/lib/docscribe/cli/config_builder.rb +107 -53
- data/lib/docscribe/cli/formatters/json.rb +294 -0
- data/lib/docscribe/cli/formatters/sarif.rb +235 -0
- data/lib/docscribe/cli/formatters/text.rb +208 -0
- data/lib/docscribe/cli/formatters.rb +26 -0
- data/lib/docscribe/cli/generate.rb +56 -62
- data/lib/docscribe/cli/init.rb +14 -6
- data/lib/docscribe/cli/options.rb +206 -89
- data/lib/docscribe/cli/rbs_gen.rb +529 -0
- data/lib/docscribe/cli/run.rb +433 -154
- data/lib/docscribe/cli/server.rb +135 -0
- data/lib/docscribe/cli/sigs.rb +366 -0
- data/lib/docscribe/cli/update_types.rb +103 -0
- data/lib/docscribe/cli.rb +21 -24
- data/lib/docscribe/config/defaults.rb +7 -2
- data/lib/docscribe/config/emit.rb +17 -0
- data/lib/docscribe/config/filtering.rb +17 -24
- data/lib/docscribe/config/loader.rb +19 -17
- data/lib/docscribe/config/plugin.rb +1 -1
- data/lib/docscribe/config/rbs.rb +39 -7
- data/lib/docscribe/config/sorbet.rb +22 -16
- data/lib/docscribe/config/sorting.rb +1 -1
- data/lib/docscribe/config/template.rb +10 -1
- data/lib/docscribe/config/utils.rb +11 -9
- data/lib/docscribe/config.rb +10 -6
- data/lib/docscribe/infer/ast_walk.rb +1 -1
- data/lib/docscribe/infer/literals.rb +6 -11
- data/lib/docscribe/infer/names.rb +2 -3
- data/lib/docscribe/infer/params.rb +14 -16
- data/lib/docscribe/infer/raises.rb +3 -5
- data/lib/docscribe/infer/returns.rb +615 -151
- data/lib/docscribe/infer.rb +29 -26
- data/lib/docscribe/inline_rewriter/collector.rb +159 -164
- data/lib/docscribe/inline_rewriter/doc_block.rb +145 -115
- data/lib/docscribe/inline_rewriter/doc_builder.rb +1032 -723
- data/lib/docscribe/inline_rewriter/source_helpers.rb +48 -48
- data/lib/docscribe/inline_rewriter/tag_sorter.rb +82 -85
- data/lib/docscribe/inline_rewriter.rb +485 -488
- data/lib/docscribe/lru_cache.rb +49 -0
- data/lib/docscribe/parsing.rb +28 -9
- data/lib/docscribe/plugin/base/collector_plugin.rb +2 -1
- data/lib/docscribe/plugin/base/tag_plugin.rb +0 -1
- data/lib/docscribe/plugin/context.rb +28 -18
- data/lib/docscribe/plugin/registry.rb +25 -26
- data/lib/docscribe/plugin/tag.rb +9 -14
- data/lib/docscribe/plugin.rb +17 -16
- data/lib/docscribe/server.rb +608 -0
- data/lib/docscribe/types/provider_chain.rb +4 -2
- data/lib/docscribe/types/rbs/collection_loader.rb +2 -2
- data/lib/docscribe/types/rbs/provider.rb +177 -51
- data/lib/docscribe/types/rbs/type_formatter.rb +224 -83
- data/lib/docscribe/types/signature.rb +22 -42
- data/lib/docscribe/types/sorbet/base_provider.rb +29 -21
- data/lib/docscribe/types/sorbet/rbi_provider.rb +6 -5
- data/lib/docscribe/types/sorbet/source_provider.rb +6 -4
- data/lib/docscribe/types/yard/formatter.rb +100 -0
- data/lib/docscribe/types/yard/parser.rb +240 -0
- data/lib/docscribe/types/yard/types.rb +52 -0
- data/lib/docscribe/version.rb +1 -1
- metadata +38 -1
|
@@ -139,5 +139,22 @@ module Docscribe
|
|
|
139
139
|
def include_param_documentation?
|
|
140
140
|
fetch_bool(%w[emit include_param_documentation], true)
|
|
141
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
|
|
142
159
|
end
|
|
143
160
|
end
|
|
@@ -9,7 +9,6 @@ module Docscribe
|
|
|
9
9
|
# Exclude rules win. If no include rules are configured, files are included by default.
|
|
10
10
|
#
|
|
11
11
|
# @param [String] path file path to test
|
|
12
|
-
# @raise [StandardError]
|
|
13
12
|
# @return [Boolean]
|
|
14
13
|
def process_file?(path)
|
|
15
14
|
include_patterns, exclude_patterns = load_file_patterns
|
|
@@ -23,8 +22,7 @@ module Docscribe
|
|
|
23
22
|
|
|
24
23
|
# Load normalized file include/exclude patterns from config.
|
|
25
24
|
#
|
|
26
|
-
# @
|
|
27
|
-
# @return [Array(Array<String>, Array<String>)] include_patterns, exclude_patterns
|
|
25
|
+
# @return [(Array<String>, Array<String>)]
|
|
28
26
|
def load_file_patterns
|
|
29
27
|
files = raw.dig('filter', 'files') || {}
|
|
30
28
|
[normalize_file_patterns(files['include']), normalize_file_patterns(files['exclude'])]
|
|
@@ -32,10 +30,10 @@ module Docscribe
|
|
|
32
30
|
|
|
33
31
|
# Compute the relative path for filtering.
|
|
34
32
|
#
|
|
35
|
-
# @
|
|
36
|
-
# @param [String] path
|
|
33
|
+
# @param [String] path file path to test
|
|
37
34
|
# @raise [StandardError]
|
|
38
35
|
# @return [String]
|
|
36
|
+
# @return [String] if StandardError
|
|
39
37
|
def relative_path(path)
|
|
40
38
|
Pathname.new(path).expand_path.relative_path_from(Pathname.pwd).cleanpath.to_s
|
|
41
39
|
rescue StandardError
|
|
@@ -76,8 +74,7 @@ module Docscribe
|
|
|
76
74
|
# - remove empties
|
|
77
75
|
# - expand shorthand directory forms
|
|
78
76
|
#
|
|
79
|
-
# @
|
|
80
|
-
# @param [Array<String>, nil] list raw pattern list
|
|
77
|
+
# @param [Array<String>?] list raw pattern list
|
|
81
78
|
# @return [Array<String>]
|
|
82
79
|
def normalize_file_patterns(list)
|
|
83
80
|
Array(list).compact.map(&:to_s).reject(&:empty?).flat_map { |pat| expand_directory_shorthand(pat) }.uniq
|
|
@@ -89,8 +86,7 @@ module Docscribe
|
|
|
89
86
|
# - `"spec/"` => `"spec/**/*"`
|
|
90
87
|
# - `"spec"` => `"spec/**/*"` if `spec` exists as a directory
|
|
91
88
|
#
|
|
92
|
-
# @
|
|
93
|
-
# @param [String] pattern
|
|
89
|
+
# @param [String] pattern file pattern to expand
|
|
94
90
|
# @return [Array<String>]
|
|
95
91
|
def expand_directory_shorthand(pattern)
|
|
96
92
|
pat = pattern.dup
|
|
@@ -106,9 +102,8 @@ module Docscribe
|
|
|
106
102
|
|
|
107
103
|
# Check whether a file path matches any configured file pattern.
|
|
108
104
|
#
|
|
109
|
-
# @
|
|
110
|
-
# @param [
|
|
111
|
-
# @param [String] path
|
|
105
|
+
# @param [Array<String>] patterns file filter patterns
|
|
106
|
+
# @param [String] path file path to test
|
|
112
107
|
# @return [Boolean]
|
|
113
108
|
def file_matches_any?(patterns, path)
|
|
114
109
|
patterns.any? { |pat| file_match_pattern?(pat, path) }
|
|
@@ -121,13 +116,12 @@ module Docscribe
|
|
|
121
116
|
# - globs
|
|
122
117
|
# - recursive glob shorthand normalization
|
|
123
118
|
#
|
|
124
|
-
# @
|
|
125
|
-
# @param [String]
|
|
126
|
-
# @param [String] path
|
|
119
|
+
# @param [String] pattern file filter pattern
|
|
120
|
+
# @param [String] path file path to test
|
|
127
121
|
# @return [Boolean]
|
|
128
122
|
def file_match_pattern?(pattern, path)
|
|
129
123
|
if pattern.start_with?('/') && pattern.end_with?('/') && pattern.length >= 2
|
|
130
|
-
return Regexp.new(pattern[1..-2]).match?(path)
|
|
124
|
+
return Regexp.new(pattern[1..-2]).match?(path) # steep:ignore
|
|
131
125
|
end
|
|
132
126
|
|
|
133
127
|
patterns_to_try = [pattern]
|
|
@@ -140,34 +134,33 @@ module Docscribe
|
|
|
140
134
|
|
|
141
135
|
# Allowed method scopes from config/defaults.
|
|
142
136
|
#
|
|
143
|
-
# @private
|
|
144
137
|
# @return [Array<String>]
|
|
145
138
|
def filter_scopes
|
|
146
|
-
Array(raw.dig('filter', 'scopes') || DEFAULT.dig('filter', 'scopes')).map(&:to_s)
|
|
139
|
+
Array(raw.dig('filter', 'scopes') || DEFAULT.dig('filter', 'scopes')).map(&:to_s) # steep:ignore
|
|
147
140
|
end
|
|
148
141
|
|
|
149
142
|
# Allowed method visibilities from config/defaults.
|
|
150
143
|
#
|
|
151
|
-
# @private
|
|
152
144
|
# @return [Array<String>]
|
|
153
145
|
def filter_visibilities
|
|
154
|
-
Array(raw.dig('filter', 'visibilities') ||
|
|
146
|
+
Array(raw.dig('filter', 'visibilities') ||
|
|
147
|
+
DEFAULT.dig('filter', 'visibilities')).map(&:to_s) # steep:ignore
|
|
155
148
|
end
|
|
156
149
|
|
|
157
150
|
# Exclude method filter patterns.
|
|
158
151
|
#
|
|
159
|
-
# @private
|
|
160
152
|
# @return [Array<String>]
|
|
161
153
|
def filter_exclude_patterns
|
|
162
|
-
Array(raw.dig('filter', 'exclude') ||
|
|
154
|
+
Array(raw.dig('filter', 'exclude') ||
|
|
155
|
+
DEFAULT.dig('filter', 'exclude')).map(&:to_s).reject(&:empty?) # steep:ignore
|
|
163
156
|
end
|
|
164
157
|
|
|
165
158
|
# Include method filter patterns.
|
|
166
159
|
#
|
|
167
|
-
# @private
|
|
168
160
|
# @return [Array<String>]
|
|
169
161
|
def filter_include_patterns
|
|
170
|
-
Array(raw.dig('filter', 'include') ||
|
|
162
|
+
Array(raw.dig('filter', 'include') ||
|
|
163
|
+
DEFAULT.dig('filter', 'include')).map(&:to_s).reject(&:empty?) # steep:ignore
|
|
171
164
|
end
|
|
172
165
|
end
|
|
173
166
|
end
|
|
@@ -10,16 +10,14 @@ module Docscribe
|
|
|
10
10
|
# - `docscribe.yml` in the current directory, if present
|
|
11
11
|
# - otherwise defaults only
|
|
12
12
|
#
|
|
13
|
-
# @param [String
|
|
13
|
+
# @param [String?] path optional config path
|
|
14
14
|
# @return [Docscribe::Config]
|
|
15
15
|
def self.load(path = nil)
|
|
16
16
|
raw = {} #: Hash[String, untyped]
|
|
17
|
-
if path && File.file?(path)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
end
|
|
22
|
-
new(raw)
|
|
17
|
+
resolved = path if path && File.file?(path)
|
|
18
|
+
resolved ||= 'docscribe.yml' if File.file?('docscribe.yml')
|
|
19
|
+
raw = safe_load_file_compat(resolved) if resolved
|
|
20
|
+
new(config_path: resolved, **raw) # steep:ignore
|
|
23
21
|
end
|
|
24
22
|
|
|
25
23
|
# Safely load YAML from a file across Ruby/Psych versions.
|
|
@@ -28,11 +26,13 @@ module Docscribe
|
|
|
28
26
|
# and calling {safe_load_compat}.
|
|
29
27
|
#
|
|
30
28
|
# @param [String] path file path
|
|
31
|
-
# @return [Hash]
|
|
29
|
+
# @return [Hash<String, Object>]
|
|
32
30
|
def self.safe_load_file_compat(path)
|
|
33
|
-
if YAML.respond_to?(:safe_load_file)
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
if YAML.respond_to?(:safe_load_file) # steep:ignore
|
|
32
|
+
pclasses = [] #: Array[String]
|
|
33
|
+
psymbols = [] #: Array[Symbol]
|
|
34
|
+
YAML.safe_load_file(path, # steep:ignore
|
|
35
|
+
permitted_classes: pclasses, permitted_symbols: psymbols,
|
|
36
36
|
aliases: true) || {} #: Hash[String, untyped]
|
|
37
37
|
else
|
|
38
38
|
yaml = File.open(path, 'r:bom|utf-8', &:read)
|
|
@@ -43,20 +43,22 @@ module Docscribe
|
|
|
43
43
|
# Safely load YAML from a string across Psych API versions.
|
|
44
44
|
#
|
|
45
45
|
# @param [String] yaml YAML document
|
|
46
|
-
# @param [String
|
|
46
|
+
# @param [String?] filename optional filename for diagnostics
|
|
47
47
|
# @raise [ArgumentError]
|
|
48
|
-
# @return [Hash]
|
|
48
|
+
# @return [Hash<String, Object>]
|
|
49
|
+
# @return [Object] if ArgumentError
|
|
49
50
|
def self.safe_load_compat(yaml, filename: nil)
|
|
50
|
-
|
|
51
|
+
pclasses = [] #: Array[String]
|
|
52
|
+
psymbols = [] #: Array[Symbol]
|
|
53
|
+
Psych.safe_load( # steep:ignore
|
|
51
54
|
yaml,
|
|
52
|
-
permitted_classes:
|
|
53
|
-
permitted_symbols: [],
|
|
55
|
+
permitted_classes: pclasses, permitted_symbols: psymbols,
|
|
54
56
|
aliases: true,
|
|
55
57
|
filename: filename
|
|
56
58
|
) #: Hash[String, untyped]
|
|
57
59
|
rescue ArgumentError
|
|
58
60
|
# Older Psych signature uses positional args
|
|
59
|
-
Psych.safe_load(yaml, [], [], true, filename)
|
|
61
|
+
Psych.safe_load(yaml, [], [], true, filename) # steep:ignore
|
|
60
62
|
end
|
|
61
63
|
end
|
|
62
64
|
end
|
|
@@ -15,7 +15,7 @@ module Docscribe
|
|
|
15
15
|
# @raise [LoadError]
|
|
16
16
|
# @return [void]
|
|
17
17
|
def load_plugins!
|
|
18
|
-
paths = Array(raw.dig('plugins', 'require')).compact
|
|
18
|
+
paths = Array(raw.dig('plugins', 'require')).compact #: Array[String]
|
|
19
19
|
return if paths.empty?
|
|
20
20
|
|
|
21
21
|
require 'docscribe/plugin'
|
data/lib/docscribe/config/rbs.rb
CHANGED
|
@@ -8,7 +8,6 @@ module Docscribe
|
|
|
8
8
|
# If RBS cannot be loaded, this returns nil and Docscribe falls back to
|
|
9
9
|
# inference.
|
|
10
10
|
#
|
|
11
|
-
# @raise [LoadError]
|
|
12
11
|
# @return [Docscribe::Types::RBS::Provider, nil]
|
|
13
12
|
def rbs_provider
|
|
14
13
|
return nil unless rbs_enabled?
|
|
@@ -24,14 +23,25 @@ module Docscribe
|
|
|
24
23
|
fetch_bool(%w[rbs enabled], false)
|
|
25
24
|
end
|
|
26
25
|
|
|
27
|
-
#
|
|
28
|
-
#
|
|
26
|
+
# Core rbs provider
|
|
27
|
+
#
|
|
28
|
+
# @return [Docscribe::Types::RBS::Provider, nil]
|
|
29
29
|
def core_rbs_provider
|
|
30
30
|
return nil unless ruby_supports_rbs?
|
|
31
31
|
|
|
32
32
|
@core_rbs_provider ||= build_core_rbs_provider
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
# Whether to warn when rbs_collection.lock.yaml exists but --rbs-collection
|
|
36
|
+
# was not passed.
|
|
37
|
+
#
|
|
38
|
+
# Set `rbs.warn_missing_collection: false` in `docscribe.yml` to suppress.
|
|
39
|
+
#
|
|
40
|
+
# @return [Boolean]
|
|
41
|
+
def rbs_warn_missing_collection?
|
|
42
|
+
fetch_bool(%w[rbs warn_missing_collection], true)
|
|
43
|
+
end
|
|
44
|
+
|
|
35
45
|
private
|
|
36
46
|
|
|
37
47
|
# Check whether the current Ruby version supports RBS (requires 3.0+).
|
|
@@ -48,23 +58,31 @@ module Docscribe
|
|
|
48
58
|
false
|
|
49
59
|
end
|
|
50
60
|
|
|
61
|
+
# Build rbs provider
|
|
62
|
+
#
|
|
51
63
|
# @private
|
|
52
64
|
# @raise [LoadError]
|
|
53
65
|
# @return [Docscribe::Types::RBS::Provider, nil]
|
|
66
|
+
# @return [nil] if LoadError
|
|
54
67
|
def build_rbs_provider
|
|
55
68
|
require 'docscribe/types/rbs/provider'
|
|
56
69
|
Docscribe::Types::RBS::Provider.new(
|
|
57
70
|
sig_dirs: rbs_sig_dirs,
|
|
58
71
|
collection_dirs: rbs_collection_dirs,
|
|
59
|
-
collapse_generics: rbs_collapse_generics
|
|
72
|
+
collapse_generics: rbs_collapse_generics?,
|
|
73
|
+
collapse_object_generics: rbs_collapse_object_generics?
|
|
60
74
|
)
|
|
61
75
|
rescue LoadError
|
|
76
|
+
warn 'Docscribe: --rbs requires the `rbs` gem. Add `gem "rbs"` to your Gemfile and run `bundle install`.'
|
|
62
77
|
nil
|
|
63
78
|
end
|
|
64
79
|
|
|
80
|
+
# Build core rbs provider
|
|
81
|
+
#
|
|
65
82
|
# @private
|
|
66
83
|
# @raise [LoadError]
|
|
67
84
|
# @return [Docscribe::Types::RBS::Provider, nil]
|
|
85
|
+
# @return [nil] if LoadError
|
|
68
86
|
def build_core_rbs_provider
|
|
69
87
|
require 'docscribe/types/rbs/provider'
|
|
70
88
|
Docscribe::Types::RBS::Provider.new(
|
|
@@ -80,7 +98,7 @@ module Docscribe
|
|
|
80
98
|
# @private
|
|
81
99
|
# @return [Array<String>]
|
|
82
100
|
def rbs_sig_dirs
|
|
83
|
-
Array(raw.dig('rbs', 'sig_dirs') || DEFAULT.dig('rbs', 'sig_dirs')).map(&:to_s)
|
|
101
|
+
Array(raw.dig('rbs', 'sig_dirs') || DEFAULT.dig('rbs', 'sig_dirs')).map(&:to_s) # steep:ignore
|
|
84
102
|
end
|
|
85
103
|
|
|
86
104
|
# RBS collection directories (auto-discovered from rbs_collection.lock.yaml).
|
|
@@ -92,7 +110,7 @@ module Docscribe
|
|
|
92
110
|
# @private
|
|
93
111
|
# @return [Array<String>]
|
|
94
112
|
def rbs_collection_dirs
|
|
95
|
-
Array(raw.dig('rbs', 'collection_dirs')).map(&:to_s)
|
|
113
|
+
Array(raw.dig('rbs', 'collection_dirs')).map(&:to_s) # steep:ignore
|
|
96
114
|
end
|
|
97
115
|
|
|
98
116
|
# Whether generic RBS types should be collapsed to simpler container names.
|
|
@@ -102,9 +120,23 @@ module Docscribe
|
|
|
102
120
|
# - `Array<Integer>` => `Array`
|
|
103
121
|
#
|
|
104
122
|
# @private
|
|
105
|
-
# @return [
|
|
123
|
+
# @return [Boolean]
|
|
106
124
|
def rbs_collapse_generics?
|
|
107
125
|
fetch_bool(%w[rbs collapse_generics], false)
|
|
108
126
|
end
|
|
127
|
+
|
|
128
|
+
# Whether to collapse generic types when all inner types are Object.
|
|
129
|
+
#
|
|
130
|
+
# Unlike `collapse_generics` (which drops all generic info), this only
|
|
131
|
+
# collapses when the type arguments provide no useful information:
|
|
132
|
+
# - `Hash<Symbol, Object>` => stays as is (Symbol is useful)
|
|
133
|
+
# - `Hash<Object, Object>` => `Hash`
|
|
134
|
+
# - `Array<Object>` => `Array`
|
|
135
|
+
#
|
|
136
|
+
# @private
|
|
137
|
+
# @return [Boolean]
|
|
138
|
+
def rbs_collapse_object_generics?
|
|
139
|
+
fetch_bool(%w[rbs collapse_object_generics], false)
|
|
140
|
+
end
|
|
109
141
|
end
|
|
110
142
|
end
|
|
@@ -14,7 +14,6 @@ module Docscribe
|
|
|
14
14
|
#
|
|
15
15
|
# @param [String] source Ruby source being rewritten
|
|
16
16
|
# @param [String] file source name for diagnostics
|
|
17
|
-
# @raise [LoadError]
|
|
18
17
|
# @return [Docscribe::Types::ProviderChain, nil]
|
|
19
18
|
def signature_provider_for(source:, file:)
|
|
20
19
|
providers = [] #: Array[untyped]
|
|
@@ -25,10 +24,9 @@ module Docscribe
|
|
|
25
24
|
|
|
26
25
|
# Append Sorbet-based providers to the list.
|
|
27
26
|
#
|
|
28
|
-
# @
|
|
29
|
-
# @param [
|
|
30
|
-
# @param [String] source
|
|
31
|
-
# @param [String] file
|
|
27
|
+
# @param [Array<Object>] providers provider list to populate
|
|
28
|
+
# @param [String] source Ruby source being rewritten
|
|
29
|
+
# @param [String] file source name for diagnostics
|
|
32
30
|
# @return [void]
|
|
33
31
|
def append_sorbet_providers(providers, source:, file:)
|
|
34
32
|
return unless sorbet_enabled?
|
|
@@ -39,17 +37,18 @@ module Docscribe
|
|
|
39
37
|
|
|
40
38
|
# Build a Sorbet source provider (inline sigs).
|
|
41
39
|
#
|
|
42
|
-
# @
|
|
43
|
-
# @param [String] source
|
|
44
|
-
# @param [String] file
|
|
40
|
+
# @param [String] source Ruby source being rewritten
|
|
41
|
+
# @param [String] file source name for diagnostics
|
|
45
42
|
# @raise [LoadError]
|
|
46
43
|
# @return [Docscribe::Types::Sorbet::SourceProvider, nil]
|
|
44
|
+
# @return [nil] if LoadError
|
|
47
45
|
def sorbet_source_provider(source, file)
|
|
48
46
|
require 'docscribe/types/sorbet/source_provider'
|
|
49
47
|
Docscribe::Types::Sorbet::SourceProvider.new(
|
|
50
48
|
source: source,
|
|
51
49
|
file: file,
|
|
52
|
-
collapse_generics: sorbet_collapse_generics
|
|
50
|
+
collapse_generics: sorbet_collapse_generics?,
|
|
51
|
+
collapse_object_generics: sorbet_collapse_object_generics?
|
|
53
52
|
)
|
|
54
53
|
rescue LoadError
|
|
55
54
|
nil
|
|
@@ -57,8 +56,7 @@ module Docscribe
|
|
|
57
56
|
|
|
58
57
|
# Build the provider chain from a non-empty list, or return nil.
|
|
59
58
|
#
|
|
60
|
-
# @
|
|
61
|
-
# @param [Array] providers
|
|
59
|
+
# @param [Array<Object>] providers provider list to chain
|
|
62
60
|
# @return [Docscribe::Types::ProviderChain, nil]
|
|
63
61
|
def build_provider_chain(providers)
|
|
64
62
|
providers = providers.compact
|
|
@@ -77,10 +75,9 @@ module Docscribe
|
|
|
77
75
|
|
|
78
76
|
@sorbet_rbi_provider ||= begin
|
|
79
77
|
require 'docscribe/types/sorbet/rbi_provider'
|
|
80
|
-
Docscribe::Types::Sorbet::RBIProvider.new(
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
)
|
|
78
|
+
Docscribe::Types::Sorbet::RBIProvider.new(rbi_dirs: sorbet_rbi_dirs,
|
|
79
|
+
collapse_generics: sorbet_collapse_generics?,
|
|
80
|
+
collapse_object_generics: sorbet_collapse_object_generics?)
|
|
84
81
|
rescue LoadError
|
|
85
82
|
nil
|
|
86
83
|
end
|
|
@@ -97,7 +94,7 @@ module Docscribe
|
|
|
97
94
|
#
|
|
98
95
|
# @return [Array<String>]
|
|
99
96
|
def sorbet_rbi_dirs
|
|
100
|
-
Array(raw.dig('sorbet', 'rbi_dirs') || DEFAULT.dig('sorbet', 'rbi_dirs')).map(&:to_s)
|
|
97
|
+
Array(raw.dig('sorbet', 'rbi_dirs') || DEFAULT.dig('sorbet', 'rbi_dirs')).map(&:to_s) # steep:ignore
|
|
101
98
|
end
|
|
102
99
|
|
|
103
100
|
# Whether generic Sorbet/RBI container types should be simplified.
|
|
@@ -109,5 +106,14 @@ module Docscribe
|
|
|
109
106
|
def sorbet_collapse_generics?
|
|
110
107
|
fetch_bool(%w[sorbet collapse_generics], rbs_collapse_generics?)
|
|
111
108
|
end
|
|
109
|
+
|
|
110
|
+
# Whether to collapse Object-typed generics in Sorbet types.
|
|
111
|
+
#
|
|
112
|
+
# Falls back to the RBS setting when Sorbet-specific config is not present.
|
|
113
|
+
#
|
|
114
|
+
# @return [Boolean]
|
|
115
|
+
def sorbet_collapse_object_generics?
|
|
116
|
+
fetch_bool(%w[sorbet collapse_object_generics], rbs_collapse_object_generics?)
|
|
117
|
+
end
|
|
112
118
|
end
|
|
113
119
|
end
|
|
@@ -7,7 +7,6 @@ module Docscribe
|
|
|
7
7
|
#
|
|
8
8
|
# The template documents the most common CLI workflows and all supported
|
|
9
9
|
# configuration sections with comments.
|
|
10
|
-
# @see Docscribe::Config::DEFAULT
|
|
11
10
|
#
|
|
12
11
|
# @return [String]
|
|
13
12
|
def self.default_yaml
|
|
@@ -21,6 +20,7 @@ module Docscribe
|
|
|
21
20
|
# bundle exec docscribe lib # check what would change
|
|
22
21
|
# bundle exec docscribe -a lib # apply safe updates
|
|
23
22
|
# bundle exec docscribe -A lib # rebuild all doc blocks
|
|
23
|
+
# bundle exec docscribe -AkB lib # rebuild, keep descriptions, no boilerplate
|
|
24
24
|
|
|
25
25
|
emit:
|
|
26
26
|
# What to include in generated documentation
|
|
@@ -89,13 +89,22 @@ module Docscribe
|
|
|
89
89
|
sig_dirs: ["sig"]
|
|
90
90
|
collection_dirs: [] # auto-discovered from --rbs-collection
|
|
91
91
|
collapse_generics: false # Hash<Symbol, String> => Hash
|
|
92
|
+
collapse_object_generics: false # Hash<Object, Object> => Hash (keep if inner types are useful)
|
|
92
93
|
collection: false # auto-discover from rbs_collection.lock.yaml
|
|
94
|
+
warn_missing_collection: true # warn if rbs_collection.lock.yaml exists without --rbs-collection
|
|
93
95
|
|
|
94
96
|
sorbet:
|
|
95
97
|
# Use Sorbet inline sigs and RBI files for better types
|
|
96
98
|
enabled: false
|
|
97
99
|
rbi_dirs: ["sorbet/rbi", "rbi"]
|
|
98
100
|
collapse_generics: false
|
|
101
|
+
collapse_object_generics: false
|
|
102
|
+
|
|
103
|
+
# Preserve existing @param/@return descriptions in aggressive mode
|
|
104
|
+
keep_descriptions: false
|
|
105
|
+
|
|
106
|
+
# Skip @param for anonymous block arguments (&) (Ruby 3.2+)
|
|
107
|
+
skip_anonymous_block_params: false
|
|
99
108
|
|
|
100
109
|
plugins:
|
|
101
110
|
# Load custom plugins
|
|
@@ -46,7 +46,7 @@ module Docscribe
|
|
|
46
46
|
# Convert an internal scope symbol into the config key used under `methods`.
|
|
47
47
|
#
|
|
48
48
|
# @private
|
|
49
|
-
# @param [Symbol] scope
|
|
49
|
+
# @param [Symbol] scope :instance or :class
|
|
50
50
|
# @return [String]
|
|
51
51
|
def scope_to_key(scope)
|
|
52
52
|
scope == :class ? 'class' : 'instance'
|
|
@@ -55,8 +55,8 @@ module Docscribe
|
|
|
55
55
|
# Check whether any pattern matches the given text.
|
|
56
56
|
#
|
|
57
57
|
# @private
|
|
58
|
-
# @param [Array<String>] patterns
|
|
59
|
-
# @param [String] text
|
|
58
|
+
# @param [Array<String>] patterns filter patterns to match
|
|
59
|
+
# @param [String] text text to test against patterns
|
|
60
60
|
# @return [Boolean]
|
|
61
61
|
def matches_any?(patterns, text)
|
|
62
62
|
patterns.any? { |pat| match_pattern?(pat, text) }
|
|
@@ -69,12 +69,14 @@ module Docscribe
|
|
|
69
69
|
# - shell-style glob patterns (with `/` translated to `#` since method IDs use `#`)
|
|
70
70
|
#
|
|
71
71
|
# @private
|
|
72
|
-
# @param [String] pattern
|
|
73
|
-
# @param [String] text
|
|
72
|
+
# @param [String] pattern filter pattern to match
|
|
73
|
+
# @param [String] text method ID to test
|
|
74
74
|
# @return [Boolean]
|
|
75
75
|
def match_pattern?(pattern, text)
|
|
76
76
|
if pattern.start_with?('/') && pattern.end_with?('/') && pattern.length >= 2
|
|
77
|
-
Regexp.new(pattern[1..-2]).match?(text)
|
|
77
|
+
Regexp.new(pattern[1..-2]).match?(text) # steep:ignore
|
|
78
|
+
elsif pattern.count('*?[{').zero?
|
|
79
|
+
File.fnmatch?("*#{pattern.tr('/', '#')}*", text, File::FNM_EXTGLOB)
|
|
78
80
|
else
|
|
79
81
|
File.fnmatch?(pattern.tr('/', '#'), text, File::FNM_EXTGLOB)
|
|
80
82
|
end
|
|
@@ -85,9 +87,9 @@ module Docscribe
|
|
|
85
87
|
# Nested hashes are merged recursively; non-hash values are replaced.
|
|
86
88
|
#
|
|
87
89
|
# @private
|
|
88
|
-
# @param [Hash] hash1 base hash
|
|
89
|
-
# @param [Hash, nil] hash2 override hash
|
|
90
|
-
# @return [Hash]
|
|
90
|
+
# @param [Hash<Object, Object>] hash1 base hash
|
|
91
|
+
# @param [Hash<Object, Object>, nil] hash2 override hash
|
|
92
|
+
# @return [Hash<Object, Object>]
|
|
91
93
|
def deep_merge(hash1, hash2)
|
|
92
94
|
return hash1 unless hash2
|
|
93
95
|
|
data/lib/docscribe/config.rb
CHANGED
|
@@ -7,20 +7,24 @@ require 'psych'
|
|
|
7
7
|
module Docscribe
|
|
8
8
|
# Application configuration with deep-merge defaults and overrides.
|
|
9
9
|
class Config
|
|
10
|
-
# Raw config hash after deep-merging user config with defaults.
|
|
11
|
-
#
|
|
12
10
|
# @!attribute [r] raw
|
|
13
|
-
# @return [Hash]
|
|
11
|
+
# @return [Hash<String, Object>]
|
|
14
12
|
attr_reader :raw
|
|
15
13
|
|
|
14
|
+
# @!attribute [r] config_path
|
|
15
|
+
# @return [String?]
|
|
16
|
+
attr_reader :config_path
|
|
17
|
+
|
|
16
18
|
# Create a configuration object from a raw config hash.
|
|
17
19
|
#
|
|
18
20
|
# Missing keys are filled from {DEFAULT} via deep merge.
|
|
19
21
|
#
|
|
20
|
-
# @param [
|
|
22
|
+
# @param [String?] config_path optional path to the config file
|
|
23
|
+
# @param [Hash<String, Object>] raw user-provided config hash
|
|
21
24
|
# @return [void]
|
|
22
|
-
def initialize(
|
|
23
|
-
@raw = deep_merge(DEFAULT, raw
|
|
25
|
+
def initialize(config_path: nil, **raw)
|
|
26
|
+
@raw = deep_merge(DEFAULT, raw)
|
|
27
|
+
@config_path = config_path
|
|
24
28
|
end
|
|
25
29
|
end
|
|
26
30
|
end
|
|
@@ -11,7 +11,7 @@ module Docscribe
|
|
|
11
11
|
# Yields each node exactly once, descending recursively through child nodes.
|
|
12
12
|
# Non-AST values are ignored.
|
|
13
13
|
#
|
|
14
|
-
# @note module_function:
|
|
14
|
+
# @note module_function: defines #walk (visibility: private)
|
|
15
15
|
# @param [Parser::AST::Node, nil] node root AST node
|
|
16
16
|
# @param [Proc] block visitor block
|
|
17
17
|
# @return [void]
|
|
@@ -17,7 +17,7 @@ module Docscribe
|
|
|
17
17
|
#
|
|
18
18
|
# If the node does not match a supported pattern, the fallback type is returned.
|
|
19
19
|
#
|
|
20
|
-
# @note module_function:
|
|
20
|
+
# @note module_function: defines #type_from_literal (visibility: private)
|
|
21
21
|
# @param [Parser::AST::Node, nil] node literal/value node
|
|
22
22
|
# @param [String] fallback_type type returned when inference is uncertain
|
|
23
23
|
# @return [String]
|
|
@@ -30,8 +30,7 @@ module Docscribe
|
|
|
30
30
|
|
|
31
31
|
# Map a node type symbol to a known literal type name.
|
|
32
32
|
#
|
|
33
|
-
# @note module_function:
|
|
34
|
-
# @private
|
|
33
|
+
# @note module_function: defines #literal_type_for (visibility: private)
|
|
35
34
|
# @param [Symbol] type node type
|
|
36
35
|
# @return [String, nil]
|
|
37
36
|
def literal_type_for(type)
|
|
@@ -40,10 +39,8 @@ module Docscribe
|
|
|
40
39
|
|
|
41
40
|
# Extract a constant name from a `:const` node.
|
|
42
41
|
#
|
|
43
|
-
# @note module_function:
|
|
44
|
-
# @
|
|
45
|
-
# @param [Parser::AST::Node] node
|
|
46
|
-
# @param [String] fallback_type
|
|
42
|
+
# @note module_function: defines #const_type_for (visibility: private)
|
|
43
|
+
# @param [Parser::AST::Node] node literal/value node
|
|
47
44
|
# @param [String] _fallback_type fallback type string (unused here)
|
|
48
45
|
# @return [String, nil]
|
|
49
46
|
def const_type_for(node, _fallback_type)
|
|
@@ -54,10 +51,8 @@ module Docscribe
|
|
|
54
51
|
|
|
55
52
|
# Extract a type from a `Foo.new` send node.
|
|
56
53
|
#
|
|
57
|
-
# @note module_function:
|
|
58
|
-
# @
|
|
59
|
-
# @param [Parser::AST::Node] node
|
|
60
|
-
# @param [String] fallback_type
|
|
54
|
+
# @note module_function: defines #send_new_type_for (visibility: private)
|
|
55
|
+
# @param [Parser::AST::Node] node literal/value node
|
|
61
56
|
# @param [String] _fallback_type fallback type string (unused here)
|
|
62
57
|
# @return [String, nil]
|
|
63
58
|
def send_new_type_for(node, _fallback_type)
|
|
@@ -15,7 +15,7 @@ module Docscribe
|
|
|
15
15
|
#
|
|
16
16
|
# Returns nil for unsupported nodes.
|
|
17
17
|
#
|
|
18
|
-
# @note module_function:
|
|
18
|
+
# @note module_function: defines #const_full_name (visibility: private)
|
|
19
19
|
# @param [Parser::AST::Node, nil] node constant-like AST node
|
|
20
20
|
# @return [String, nil]
|
|
21
21
|
def const_full_name(node)
|
|
@@ -31,8 +31,7 @@ module Docscribe
|
|
|
31
31
|
|
|
32
32
|
# Build the fully qualified name from a `:const` node.
|
|
33
33
|
#
|
|
34
|
-
# @note module_function:
|
|
35
|
-
# @private
|
|
34
|
+
# @note module_function: defines #build_const_full_name (visibility: private)
|
|
36
35
|
# @param [Parser::AST::Node] node a `:const` node
|
|
37
36
|
# @return [String]
|
|
38
37
|
def build_const_full_name(node)
|