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
@@ -10,11 +10,12 @@ module Docscribe
10
10
  # This provider parses the source being rewritten and indexes any leading
11
11
  # `sig` declarations it can resolve through the RBS RBI prototype bridge.
12
12
  class SourceProvider < BaseProvider
13
+ # Initialize
14
+ #
13
15
  # @param [String] source Ruby source containing inline `sig` declarations
14
16
  # @param [String] file source label used in diagnostics/debug warnings
15
17
  # @param [Boolean] collapse_generics whether generic container types
16
- # should be simplified during formatting
17
- # @return [Object]
18
+ # @return [void]
18
19
  def initialize(source:, file:, collapse_generics: false)
19
20
  super(collapse_generics: collapse_generics)
20
21
  load_from_string(source, label: file)
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'types'
4
+
5
+ module Docscribe
6
+ module Types
7
+ module Yard
8
+ # Converts YARD type AST to RBS type strings
9
+ module Formatter
10
+ class << self
11
+ # @param [Docscribe::Types::Yard::node?] node
12
+ # @return [String]
13
+ def to_rbs(node) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
14
+ return 'untyped' if node.nil?
15
+
16
+ case node
17
+ when Named then format_named(node)
18
+ when Generic then format_generic(node)
19
+ when Union then format_union(node)
20
+ when Intersection then format_intersection(node)
21
+ when Optional then format_optional(node)
22
+ when Tuple then format_tuple(node)
23
+ when HashMap then format_hash_map(node)
24
+ when Literal then format_literal(node)
25
+ else 'untyped'
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ # @private
32
+ # @param [Docscribe::Types::Yard::Named] node
33
+ # @return [String]
34
+ def format_named(node)
35
+ case node.name
36
+ when 'Boolean' then 'bool'
37
+ when 'Object' then 'untyped'
38
+ else node.name
39
+ end
40
+ end
41
+
42
+ # @private
43
+ # @param [Docscribe::Types::Yard::Generic] node
44
+ # @return [String]
45
+ def format_generic(node)
46
+ "#{node.base}[#{node.args.map { |a| to_rbs(a) }.join(', ')}]"
47
+ end
48
+
49
+ # @private
50
+ # @param [Docscribe::Types::Yard::Union] node
51
+ # @return [String]
52
+ def format_union(node)
53
+ node.types.map { |t| to_rbs(t) }.join(' | ')
54
+ end
55
+
56
+ # @private
57
+ # @param [Docscribe::Types::Yard::Intersection] node
58
+ # @return [String]
59
+ def format_intersection(node)
60
+ node.types.map { |t| to_rbs(t) }.join(' & ')
61
+ end
62
+
63
+ # @private
64
+ # @param [Docscribe::Types::Yard::Optional] node
65
+ # @return [String]
66
+ def format_optional(node)
67
+ "#{to_rbs(node.type)}?"
68
+ end
69
+
70
+ # @private
71
+ # @param [Docscribe::Types::Yard::Tuple] node
72
+ # @return [String]
73
+ def format_tuple(node)
74
+ "[#{node.types.map { |t| to_rbs(t) }.join(', ')}]"
75
+ end
76
+
77
+ # @private
78
+ # @param [Docscribe::Types::Yard::HashMap] node
79
+ # @return [String]
80
+ def format_hash_map(node)
81
+ "Hash[#{to_rbs(node.key_type)}, #{to_rbs(node.value_type)}]"
82
+ end
83
+
84
+ # @private
85
+ # @param [Docscribe::Types::Yard::Literal] node
86
+ # @return [String]
87
+ def format_literal(node)
88
+ case node.value
89
+ when 'void' then 'void'
90
+ when 'nil' then 'nil'
91
+ when 'self' then 'self'
92
+ when 'true', 'false' then 'bool'
93
+ else 'untyped'
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'types'
4
+
5
+ module Docscribe
6
+ module Types
7
+ # YARD type parser
8
+ module Yard
9
+ class << self
10
+ # @param [String?] string
11
+ # @return [Docscribe::Types::Yard::node?]
12
+ def parse(string)
13
+ return nil if string.nil? || string.strip.empty?
14
+
15
+ Parser.new(string).parse
16
+ end
17
+ end
18
+
19
+ # Parses YARD type strings into an AST
20
+ class Parser
21
+ # @param [String] string
22
+ # @return [void]
23
+ def initialize(string)
24
+ @s = string.strip
25
+ @i = 0
26
+ end
27
+
28
+ # @return [Docscribe::Types::Yard::node]
29
+ def parse
30
+ skip_space
31
+ node = parse_union
32
+ skip_space
33
+ node
34
+ end
35
+
36
+ private
37
+
38
+ # @private
39
+ # @return [Docscribe::Types::Yard::node]
40
+ def parse_union
41
+ types = [parse_intersection]
42
+ skip_space
43
+ while @i < @s.length && @s[@i] == ','
44
+ @i += 1
45
+ skip_space
46
+ types << parse_intersection
47
+ skip_space
48
+ end
49
+ types.size == 1 ? types.first : Union.new(types: types)
50
+ end
51
+
52
+ # @private
53
+ # @return [Docscribe::Types::Yard::node]
54
+ def parse_intersection
55
+ types = [parse_optional]
56
+ skip_space
57
+ while @i < @s.length && @s[@i] == '&'
58
+ @i += 1
59
+ skip_space
60
+ types << parse_optional
61
+ skip_space
62
+ end
63
+ types.size == 1 ? types.first : Intersection.new(types: types)
64
+ end
65
+
66
+ # @private
67
+ # @return [Docscribe::Types::Yard::node]
68
+ def parse_optional
69
+ type = parse_primary
70
+ skip_space
71
+ if @i < @s.length && @s[@i] == '?'
72
+ @i += 1
73
+ Optional.new(type: type)
74
+ else
75
+ type
76
+ end
77
+ end
78
+
79
+ # @private
80
+ # @return [Docscribe::Types::Yard::node]
81
+ def parse_primary
82
+ skip_space
83
+ case peek
84
+ when '(' then parse_tuple
85
+ when '{' then parse_hash_map
86
+ when '#' then parse_duck_type
87
+ else
88
+ parse_named_type
89
+ end
90
+ end
91
+
92
+ # @private
93
+ # @return [Docscribe::Types::Yard::Named, Docscribe::Types::Yard::Literal, Docscribe::Types::Yard::Generic, Docscribe::Types::Yard::HashMap]
94
+ def parse_named_type
95
+ name = scan_name
96
+ return Literal.new(value: name) if literal?(name)
97
+
98
+ skip_space
99
+ if @i < @s.length && @s[@i] == '<'
100
+ parse_generic(Named.new(name: name))
101
+ elsif @i < @s.length && @s[@i] == '{'
102
+ parse_named_hash_map
103
+ else
104
+ Named.new(name: name)
105
+ end
106
+ end
107
+
108
+ # @private
109
+ # @param [Docscribe::Types::Yard::Named] base
110
+ # @return [Docscribe::Types::Yard::Generic]
111
+ def parse_generic(base)
112
+ @i += 1
113
+ args = parse_generic_args
114
+ @i += 1 if @i < @s.length && @s[@i] == '>'
115
+ Generic.new(base: base.name, args: args)
116
+ end
117
+
118
+ # @private
119
+ # @return [Docscribe::Types::Yard::node]
120
+ def parse_generic_arg
121
+ types = [parse_intersection]
122
+ skip_space
123
+ while @i < @s.length && @s[@i] == '|'
124
+ @i += 1
125
+ skip_space
126
+ types << parse_intersection
127
+ skip_space
128
+ end
129
+ types.size == 1 ? types.first : Union.new(types: types)
130
+ end
131
+
132
+ # @private
133
+ # @return [Array<Docscribe::Types::Yard::node>]
134
+ def parse_generic_args
135
+ args = [] #: Array[untyped]
136
+ skip_space
137
+ while @i < @s.length && @s[@i] != '>'
138
+ args << parse_generic_arg
139
+ skip_space
140
+ next unless @i < @s.length && @s[@i] == ','
141
+
142
+ @i += 1
143
+ skip_space
144
+ end
145
+ args
146
+ end
147
+
148
+ # @private
149
+ # @return [Docscribe::Types::Yard::Tuple]
150
+ def parse_tuple
151
+ @i += 1
152
+ types = [] #: Array[untyped]
153
+ while @i < @s.length && @s[@i] != ')'
154
+ types << parse_tuple_element
155
+ @i += 1 and skip_space if @s[@i] == ','
156
+ end
157
+ @i += 1 if @s[@i] == ')'
158
+ Tuple.new(types: types)
159
+ end
160
+
161
+ # @private
162
+ # @return [Docscribe::Types::Yard::node]
163
+ def parse_tuple_element
164
+ type = parse_intersection
165
+ skip_space
166
+ if @i < @s.length && @s[@i] == '?'
167
+ @i += 1
168
+ Optional.new(type: type)
169
+ else
170
+ type
171
+ end
172
+ end
173
+
174
+ # @private
175
+ # @return [Docscribe::Types::Yard::HashMap]
176
+ def parse_hash_map
177
+ @i += 1
178
+ key = parse_union
179
+ @i += 2 if @s[@i..(@i + 1)] == '=>'
180
+ value = parse_union
181
+ @i += 1 if @s[@i] == '}'
182
+ HashMap.new(key_type: key, value_type: value)
183
+ end
184
+
185
+ # @private
186
+ # @return [Docscribe::Types::Yard::HashMap]
187
+ def parse_named_hash_map
188
+ parse_hash_map
189
+ end
190
+
191
+ # @private
192
+ # @return [Docscribe::Types::Yard::Duck]
193
+ def parse_duck_type
194
+ methods = [] #: Array[String]
195
+ while @i < @s.length && @s[@i] == '#'
196
+ @i += 1
197
+ name = scan_name
198
+ methods << name
199
+ skip_space
200
+ end
201
+ Duck.new(method_names: methods)
202
+ end
203
+
204
+ # @private
205
+ # @return [String]
206
+ def scan_name
207
+ start = @i
208
+ @i += 1 while @i < @s.length && name_char?(@s[@i])
209
+ @s[start...@i]
210
+ end
211
+
212
+ # @private
213
+ # @param [String] char
214
+ # @return [Boolean]
215
+ def name_char?(char)
216
+ char.match?(/[a-zA-Z0-9_:]/)
217
+ end
218
+
219
+ # @private
220
+ # @param [String] name
221
+ # @return [Boolean]
222
+ def literal?(name)
223
+ %w[void nil self true false].include?(name)
224
+ end
225
+
226
+ # @private
227
+ # @return [void]
228
+ def skip_space
229
+ @i += 1 while @i < @s.length && @s[@i].match?(/\s/)
230
+ end
231
+
232
+ # @private
233
+ # @return [String?]
234
+ def peek
235
+ @i < @s.length ? @s[@i] : nil
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Docscribe
4
+ module Types
5
+ module Yard
6
+ # @!attribute [rw] name
7
+ # @return [String]
8
+ # @param [String] value
9
+ Named = Struct.new(:name, keyword_init: true)
10
+ # @!attribute [rw] base
11
+ # @return [String]
12
+ # @param [String] value
13
+ #
14
+ # @!attribute [rw] args
15
+ # @return [Array<Docscribe::Types::Yard::node>]
16
+ # @param [Array<Docscribe::Types::Yard::node>] value
17
+ Generic = Struct.new(:base, :args, keyword_init: true)
18
+ # @!attribute [rw] types
19
+ # @return [Array<Docscribe::Types::Yard::node>]
20
+ # @param [Array<Docscribe::Types::Yard::node>] value
21
+ Union = Struct.new(:types, keyword_init: true)
22
+ # @!attribute [rw] types
23
+ # @return [Array<Docscribe::Types::Yard::node>]
24
+ # @param [Array<Docscribe::Types::Yard::node>] value
25
+ Intersection = Struct.new(:types, keyword_init: true)
26
+ # @!attribute [rw] type
27
+ # @return [Docscribe::Types::Yard::node]
28
+ # @param [Docscribe::Types::Yard::node] value
29
+ Optional = Struct.new(:type, keyword_init: true)
30
+ # @!attribute [rw] types
31
+ # @return [Array<Docscribe::Types::Yard::node>]
32
+ # @param [Array<Docscribe::Types::Yard::node>] value
33
+ Tuple = Struct.new(:types, keyword_init: true)
34
+ # @!attribute [rw] key_type
35
+ # @return [Docscribe::Types::Yard::node]
36
+ # @param [Docscribe::Types::Yard::node] value
37
+ #
38
+ # @!attribute [rw] value_type
39
+ # @return [Docscribe::Types::Yard::node]
40
+ # @param [Docscribe::Types::Yard::node] value
41
+ HashMap = Struct.new(:key_type, :value_type, keyword_init: true)
42
+ # @!attribute [rw] method_names
43
+ # @return [Array<String>]
44
+ # @param [Array<String>] value
45
+ Duck = Struct.new(:method_names, keyword_init: true)
46
+ # @!attribute [rw] value
47
+ # @return [String]
48
+ # @param [String] value
49
+ Literal = Struct.new(:value, keyword_init: true)
50
+ end
51
+ end
52
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Docscribe
4
- VERSION = '1.4.1'
4
+ VERSION = '1.5.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docscribe
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.1
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - unurgunite
@@ -37,6 +37,20 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '1.8'
40
+ - !ruby/object:Gem::Dependency
41
+ name: irb-autosuggestions
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
40
54
  - !ruby/object:Gem::Dependency
41
55
  name: rake
42
56
  requirement: !ruby/object:Gem::Requirement
@@ -145,11 +159,19 @@ files:
145
159
  - exe/docscribe
146
160
  - lib/docscribe.rb
147
161
  - lib/docscribe/cli.rb
162
+ - lib/docscribe/cli/check_for_comments.rb
148
163
  - lib/docscribe/cli/config_builder.rb
164
+ - lib/docscribe/cli/formatters.rb
165
+ - lib/docscribe/cli/formatters/json.rb
166
+ - lib/docscribe/cli/formatters/sarif.rb
167
+ - lib/docscribe/cli/formatters/text.rb
149
168
  - lib/docscribe/cli/generate.rb
150
169
  - lib/docscribe/cli/init.rb
151
170
  - lib/docscribe/cli/options.rb
171
+ - lib/docscribe/cli/rbs_gen.rb
152
172
  - lib/docscribe/cli/run.rb
173
+ - lib/docscribe/cli/sigs.rb
174
+ - lib/docscribe/cli/update_types.rb
153
175
  - lib/docscribe/config.rb
154
176
  - lib/docscribe/config/defaults.rb
155
177
  - lib/docscribe/config/emit.rb
@@ -190,6 +212,9 @@ files:
190
212
  - lib/docscribe/types/sorbet/base_provider.rb
191
213
  - lib/docscribe/types/sorbet/rbi_provider.rb
192
214
  - lib/docscribe/types/sorbet/source_provider.rb
215
+ - lib/docscribe/types/yard/formatter.rb
216
+ - lib/docscribe/types/yard/parser.rb
217
+ - lib/docscribe/types/yard/types.rb
193
218
  - lib/docscribe/version.rb
194
219
  homepage: https://github.com/unurgunite/docscribe
195
220
  licenses:
@@ -199,6 +224,13 @@ metadata:
199
224
  source_code_uri: https://github.com/unurgunite/docscribe
200
225
  changelog_uri: https://github.com/unurgunite/docscribe/blob/master/CHANGELOG.md
201
226
  rubygems_mfa_required: 'true'
227
+ post_install_message: |
228
+ You installed docscribe 1.5.0. Your future self (and your team) thank you.
229
+
230
+ $ docscribe --help
231
+
232
+ Happy documenting!
233
+ https://github.com/unurgunite/docscribe
202
234
  rdoc_options: []
203
235
  require_paths:
204
236
  - lib
@@ -213,7 +245,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
213
245
  - !ruby/object:Gem::Version
214
246
  version: '0'
215
247
  requirements: []
216
- rubygems_version: 4.0.12
248
+ rubygems_version: 4.0.13
217
249
  specification_version: 4
218
250
  summary: Auto-generate inline YARD documentation for Ruby by analyzing code AST. Supports
219
251
  RBS and Sorbet type signatures.