docscribe 1.4.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +465 -130
- 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 +45 -45
- data/lib/docscribe/cli/init.rb +14 -6
- data/lib/docscribe/cli/options.rb +190 -88
- data/lib/docscribe/cli/rbs_gen.rb +529 -0
- data/lib/docscribe/cli/run.rb +210 -152
- data/lib/docscribe/cli/sigs.rb +366 -0
- data/lib/docscribe/cli/update_types.rb +103 -0
- data/lib/docscribe/cli.rb +21 -13
- data/lib/docscribe/config/defaults.rb +5 -1
- data/lib/docscribe/config/emit.rb +17 -0
- data/lib/docscribe/config/filtering.rb +18 -25
- data/lib/docscribe/config/loader.rb +15 -11
- data/lib/docscribe/config/plugin.rb +1 -1
- data/lib/docscribe/config/rbs.rb +41 -9
- data/lib/docscribe/config/sorbet.rb +9 -12
- data/lib/docscribe/config/sorting.rb +1 -1
- data/lib/docscribe/config/template.rb +9 -1
- data/lib/docscribe/config/utils.rb +11 -9
- data/lib/docscribe/config.rb +2 -4
- 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 +15 -17
- data/lib/docscribe/infer/raises.rb +3 -5
- data/lib/docscribe/infer/returns.rb +542 -140
- data/lib/docscribe/infer.rb +22 -23
- 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 +1026 -723
- data/lib/docscribe/inline_rewriter/source_helpers.rb +49 -49
- data/lib/docscribe/inline_rewriter/tag_sorter.rb +82 -85
- data/lib/docscribe/inline_rewriter.rb +495 -492
- data/lib/docscribe/parsing.rb +29 -10
- 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 +26 -27
- data/lib/docscribe/plugin/tag.rb +9 -14
- data/lib/docscribe/plugin.rb +17 -16
- 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 +60 -44
- 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 +24 -19
- data/lib/docscribe/types/sorbet/rbi_provider.rb +3 -3
- data/lib/docscribe/types/sorbet/source_provider.rb +3 -2
- 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 +33 -1
|
@@ -2,64 +2,44 @@
|
|
|
2
2
|
|
|
3
3
|
module Docscribe
|
|
4
4
|
module Types
|
|
5
|
-
# Simplified view of an RBS method signature for Docscribe.
|
|
6
|
-
#
|
|
7
|
-
# @!attribute return_type
|
|
8
|
-
# @return [String] formatted return type for YARD output
|
|
9
|
-
# @!attribute param_types
|
|
10
|
-
# @return [Hash{String=>String}] mapping of parameter name to formatted type
|
|
11
|
-
# @!attribute rest_positional
|
|
12
|
-
# @return [RestPositional, nil] info for `*args`
|
|
13
|
-
# @!attribute rest_keywords
|
|
14
|
-
# @return [RestKeywords, nil] info for `**kwargs`
|
|
15
|
-
#
|
|
16
5
|
# @!attribute [rw] return_type
|
|
17
|
-
# @return [
|
|
18
|
-
# @param [
|
|
6
|
+
# @return [String]
|
|
7
|
+
# @param [String] value
|
|
19
8
|
#
|
|
20
9
|
# @!attribute [rw] param_types
|
|
21
|
-
# @return [
|
|
22
|
-
# @param [
|
|
10
|
+
# @return [Hash<String, String>]
|
|
11
|
+
# @param [Hash<String, String>] value
|
|
12
|
+
#
|
|
13
|
+
# @!attribute [rw] positional_types
|
|
14
|
+
# @return [Array<String>]
|
|
15
|
+
# @param [Array<String>] value
|
|
23
16
|
#
|
|
24
17
|
# @!attribute [rw] rest_positional
|
|
25
|
-
# @return [
|
|
26
|
-
# @param [
|
|
18
|
+
# @return [Docscribe::Types::RestPositional, nil]
|
|
19
|
+
# @param [Docscribe::Types::RestPositional, nil] value
|
|
27
20
|
#
|
|
28
21
|
# @!attribute [rw] rest_keywords
|
|
29
|
-
# @return [
|
|
30
|
-
# @param [
|
|
31
|
-
MethodSignature = Struct.new(:return_type, :param_types, :rest_positional, :rest_keywords,
|
|
22
|
+
# @return [Docscribe::Types::RestKeywords, nil]
|
|
23
|
+
# @param [Docscribe::Types::RestKeywords, nil] value
|
|
24
|
+
MethodSignature = Struct.new(:return_type, :param_types, :positional_types, :rest_positional, :rest_keywords,
|
|
25
|
+
keyword_init: true)
|
|
32
26
|
|
|
33
|
-
# Simplified representation of an RBS rest-positional parameter.
|
|
34
|
-
#
|
|
35
|
-
# @!attribute name
|
|
36
|
-
# @return [String, nil] parameter name in RBS, if present
|
|
37
|
-
# @!attribute element_type
|
|
38
|
-
# @return [String] formatted element type
|
|
39
|
-
#
|
|
40
27
|
# @!attribute [rw] name
|
|
41
|
-
# @return [
|
|
42
|
-
# @param [
|
|
28
|
+
# @return [String, nil]
|
|
29
|
+
# @param [String, nil] value
|
|
43
30
|
#
|
|
44
31
|
# @!attribute [rw] element_type
|
|
45
|
-
# @return [
|
|
46
|
-
# @param [
|
|
32
|
+
# @return [String]
|
|
33
|
+
# @param [String] value
|
|
47
34
|
RestPositional = Struct.new(:name, :element_type, keyword_init: true)
|
|
48
35
|
|
|
49
|
-
# Simplified representation of an RBS rest-keyword parameter.
|
|
50
|
-
#
|
|
51
|
-
# @!attribute name
|
|
52
|
-
# @return [String, nil] parameter name in RBS, if present
|
|
53
|
-
# @!attribute type
|
|
54
|
-
# @return [String] formatted kwargs type
|
|
55
|
-
#
|
|
56
36
|
# @!attribute [rw] name
|
|
57
|
-
# @return [
|
|
58
|
-
# @param [
|
|
37
|
+
# @return [String, nil]
|
|
38
|
+
# @param [String, nil] value
|
|
59
39
|
#
|
|
60
40
|
# @!attribute [rw] type
|
|
61
|
-
# @return [
|
|
62
|
-
# @param [
|
|
41
|
+
# @return [String]
|
|
42
|
+
# @param [String] value
|
|
63
43
|
RestKeywords = Struct.new(:name, :type, keyword_init: true)
|
|
64
44
|
end
|
|
65
45
|
end
|
|
@@ -15,9 +15,10 @@ module Docscribe
|
|
|
15
15
|
# - SourceProvider => inline `sig` declarations in the current Ruby file
|
|
16
16
|
# - RBIProvider => project RBI files
|
|
17
17
|
class BaseProvider
|
|
18
|
+
# Initialize
|
|
19
|
+
#
|
|
18
20
|
# @param [Boolean] collapse_generics whether generic container details
|
|
19
|
-
#
|
|
20
|
-
# @return [Object]
|
|
21
|
+
# @return [void]
|
|
21
22
|
def initialize(collapse_generics: false)
|
|
22
23
|
require 'rbs'
|
|
23
24
|
@collapse_generics = !!collapse_generics
|
|
@@ -49,7 +50,9 @@ module Docscribe
|
|
|
49
50
|
# @raise [::RBS::BaseError]
|
|
50
51
|
# @raise [SyntaxError]
|
|
51
52
|
# @raise [StandardError]
|
|
52
|
-
# @return [void]
|
|
53
|
+
# @return [void] if ::RBS::BaseError, SyntaxError, StandardError
|
|
54
|
+
# @return [nil] if LoadError
|
|
55
|
+
# @return [nil] if ::RBS::BaseError, SyntaxError, StandardError
|
|
53
56
|
def load_from_string(source, label:)
|
|
54
57
|
return unless defined?(RubyVM::AbstractSyntaxTree)
|
|
55
58
|
|
|
@@ -82,7 +85,7 @@ module Docscribe
|
|
|
82
85
|
#
|
|
83
86
|
# @private
|
|
84
87
|
# @param [String] container normalized container name
|
|
85
|
-
# @param [Object] member
|
|
88
|
+
# @param [Object] member RBS method definition member
|
|
86
89
|
# @return [void]
|
|
87
90
|
def process_method_member(container, member)
|
|
88
91
|
return unless method_definition_member?(member)
|
|
@@ -91,13 +94,15 @@ module Docscribe
|
|
|
91
94
|
overload = member.overloads&.first
|
|
92
95
|
return unless overload
|
|
93
96
|
|
|
94
|
-
func = overload.method_type.type
|
|
97
|
+
func = overload.method_type.type #: ::RBS::Types::Function
|
|
95
98
|
@index[[container, scope, member.name.to_s.to_sym]] = build_signature(func)
|
|
96
99
|
end
|
|
97
100
|
|
|
101
|
+
# Method definition member
|
|
102
|
+
#
|
|
98
103
|
# @private
|
|
99
|
-
# @param [Object] member
|
|
100
|
-
# @return [Boolean]
|
|
104
|
+
# @param [Object] member member to check for method def
|
|
105
|
+
# @return [Boolean, nil]
|
|
101
106
|
def method_definition_member?(member)
|
|
102
107
|
defined?(::RBS::AST::Members::MethodDefinition) &&
|
|
103
108
|
member.is_a?(::RBS::AST::Members::MethodDefinition)
|
|
@@ -106,7 +111,7 @@ module Docscribe
|
|
|
106
111
|
# Convert an RBS function type into Docscribe's simplified signature model.
|
|
107
112
|
#
|
|
108
113
|
# @private
|
|
109
|
-
# @param [
|
|
114
|
+
# @param [RBS::Types::Function] func RBS function type to convert
|
|
110
115
|
# @return [Docscribe::Types::MethodSignature]
|
|
111
116
|
def build_signature(func)
|
|
112
117
|
MethodSignature.new(
|
|
@@ -120,8 +125,8 @@ module Docscribe
|
|
|
120
125
|
# Build a name => type map for ordinary positional/keyword parameters.
|
|
121
126
|
#
|
|
122
127
|
# @private
|
|
123
|
-
# @param [
|
|
124
|
-
# @return [Hash
|
|
128
|
+
# @param [RBS::Types::Function] func RBS function to extract params
|
|
129
|
+
# @return [Hash<String, String>]
|
|
125
130
|
def build_param_types(func)
|
|
126
131
|
param_types = {} #: Hash[String, String]
|
|
127
132
|
|
|
@@ -138,8 +143,8 @@ module Docscribe
|
|
|
138
143
|
# Add keyword parameters to the normalized parameter map.
|
|
139
144
|
#
|
|
140
145
|
# @private
|
|
141
|
-
# @param [Hash
|
|
142
|
-
# @param [Hash
|
|
146
|
+
# @param [Hash<String, String>] param_types normalized param type map
|
|
147
|
+
# @param [Hash<Symbol, RBS::Types::Function::Param>] keywords keyword parameter entries
|
|
143
148
|
# @return [void]
|
|
144
149
|
def add_keywords!(param_types, keywords)
|
|
145
150
|
keywords.each do |kw, p|
|
|
@@ -150,8 +155,8 @@ module Docscribe
|
|
|
150
155
|
# Add positional parameters with names to the normalized param map.
|
|
151
156
|
#
|
|
152
157
|
# @private
|
|
153
|
-
# @param [Hash
|
|
154
|
-
# @param [Array<
|
|
158
|
+
# @param [Hash<String, String>] param_types normalized param type map
|
|
159
|
+
# @param [Array<RBS::Types::Function::Param>] list positional parameter objects
|
|
155
160
|
# @return [void]
|
|
156
161
|
def add_positionals!(param_types, list)
|
|
157
162
|
list.each do |p|
|
|
@@ -164,7 +169,7 @@ module Docscribe
|
|
|
164
169
|
# Build normalized `*args` metadata.
|
|
165
170
|
#
|
|
166
171
|
# @private
|
|
167
|
-
# @param [
|
|
172
|
+
# @param [RBS::Types::Function] func RBS function for rest params
|
|
168
173
|
# @return [Docscribe::Types::RestPositional, nil]
|
|
169
174
|
def build_rest_positional(func)
|
|
170
175
|
rp = func.rest_positionals
|
|
@@ -182,7 +187,7 @@ module Docscribe
|
|
|
182
187
|
# YARD output, we expose that as a Hash keyed by Symbol.
|
|
183
188
|
#
|
|
184
189
|
# @private
|
|
185
|
-
# @param [
|
|
190
|
+
# @param [RBS::Types::Function] func RBS function for rest keywords
|
|
186
191
|
# @return [Docscribe::Types::RestKeywords, nil]
|
|
187
192
|
def build_rest_keywords(func)
|
|
188
193
|
rk = func.rest_keywords
|
|
@@ -200,7 +205,7 @@ module Docscribe
|
|
|
200
205
|
# generated comments.
|
|
201
206
|
#
|
|
202
207
|
# @private
|
|
203
|
-
# @param [
|
|
208
|
+
# @param [Docscribe::Types::RBS::TypeFormatter::rbs_type] type RBS type object to format
|
|
204
209
|
# @return [String]
|
|
205
210
|
def format_type(type)
|
|
206
211
|
Docscribe::Types::RBS::TypeFormatter.to_yard(
|
|
@@ -212,7 +217,7 @@ module Docscribe
|
|
|
212
217
|
# Normalize container names so lookups are consistent.
|
|
213
218
|
#
|
|
214
219
|
# @private
|
|
215
|
-
# @param [String] name
|
|
220
|
+
# @param [String] name method name
|
|
216
221
|
# @return [String]
|
|
217
222
|
def normalize_container(name)
|
|
218
223
|
name.to_s.delete_prefix('::')
|
|
@@ -221,7 +226,7 @@ module Docscribe
|
|
|
221
226
|
# Print one debug warning per provider instance when debugging is enabled.
|
|
222
227
|
#
|
|
223
228
|
# @private
|
|
224
|
-
# @param [String] msg
|
|
229
|
+
# @param [String] msg warning message text
|
|
225
230
|
# @return [void]
|
|
226
231
|
def warn_once(msg)
|
|
227
232
|
return unless ENV['DOCSCRIBE_RBS_DEBUG'] == '1'
|
|
@@ -12,11 +12,11 @@ module Docscribe
|
|
|
12
12
|
# any signatures that can be parsed are indexed into Docscribe's normalized
|
|
13
13
|
# signature model.
|
|
14
14
|
class RBIProvider < BaseProvider
|
|
15
|
+
# Initialize
|
|
16
|
+
#
|
|
15
17
|
# @param [Array<String>] rbi_dirs directories scanned recursively for
|
|
16
|
-
# `.rbi` files
|
|
17
18
|
# @param [Boolean] collapse_generics whether generic container types
|
|
18
|
-
#
|
|
19
|
-
# @return [Object]
|
|
19
|
+
# @return [void]
|
|
20
20
|
def initialize(rbi_dirs:, collapse_generics: false)
|
|
21
21
|
super(collapse_generics: collapse_generics)
|
|
22
22
|
|
|
@@ -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
|
-
#
|
|
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
|
data/lib/docscribe/version.rb
CHANGED