decode 0.24.2 → 0.24.4
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
- checksums.yaml.gz.sig +0 -0
- data/bake/decode/rbs.rb +1 -1
- data/context/coverage.md +1 -1
- data/context/getting-started.md +1 -1
- data/context/ruby-documentation.md +3 -3
- data/context/types.md +127 -0
- data/lib/decode/comment/attribute.rb +5 -2
- data/lib/decode/comment/constant.rb +47 -0
- data/lib/decode/comment/node.rb +32 -12
- data/lib/decode/comment/option.rb +1 -1
- data/lib/decode/comment/parameter.rb +6 -2
- data/lib/decode/comment/rbs.rb +8 -8
- data/lib/decode/comment/tag.rb +19 -0
- data/lib/decode/comment/tags.rb +16 -5
- data/lib/decode/comment/text.rb +1 -0
- data/lib/decode/comment/yields.rb +5 -1
- data/lib/decode/definition.rb +33 -31
- data/lib/decode/documentation.rb +10 -5
- data/lib/decode/index.rb +12 -7
- data/lib/decode/language/generic.rb +10 -1
- data/lib/decode/language/reference.rb +7 -4
- data/lib/decode/language/ruby/class.rb +2 -2
- data/lib/decode/language/ruby/code.rb +21 -3
- data/lib/decode/language/ruby/definition.rb +15 -3
- data/lib/decode/language/ruby/generic.rb +2 -1
- data/lib/decode/language/ruby/parser.rb +132 -91
- data/lib/decode/language/ruby/reference.rb +4 -1
- data/lib/decode/language/ruby/segment.rb +2 -2
- data/lib/decode/languages.rb +29 -8
- data/lib/decode/location.rb +12 -1
- data/lib/decode/rbs/class.rb +91 -14
- data/lib/decode/rbs/generator.rb +67 -11
- data/lib/decode/rbs/method.rb +394 -65
- data/lib/decode/rbs/module.rb +81 -5
- data/lib/decode/rbs/type.rb +51 -0
- data/lib/decode/rbs/wrapper.rb +10 -3
- data/lib/decode/scope.rb +2 -2
- data/lib/decode/segment.rb +3 -2
- data/lib/decode/source.rb +5 -14
- data/lib/decode/syntax/rewriter.rb +4 -1
- data/lib/decode/trie.rb +29 -21
- data/lib/decode/version.rb +2 -1
- data/readme.md +6 -0
- data/releases.md +6 -0
- data/sig/decode.rbs +1189 -0
- data.tar.gz.sig +0 -0
- metadata +5 -15
- metadata.gz.sig +0 -0
data/lib/decode/definition.rb
CHANGED
@@ -10,10 +10,11 @@ module Decode
|
|
10
10
|
class Definition
|
11
11
|
# Initialize the symbol.
|
12
12
|
# @parameter path [Symbol | Array(Symbol)] The path of the definition relatve to the parent.
|
13
|
-
# @parameter parent [
|
14
|
-
# @parameter language [Language] The language in which the symbol is defined in.
|
15
|
-
# @parameter comments [Array(String)] The comments associated with the definition.
|
16
|
-
# @parameter
|
13
|
+
# @parameter parent [Definition?] The parent lexical scope.
|
14
|
+
# @parameter language [Language::Generic?] The language in which the symbol is defined in.
|
15
|
+
# @parameter comments [Array(String)?] The comments associated with the definition.
|
16
|
+
# @parameter visibility [Symbol] The visibility of the definition.
|
17
|
+
# @parameter source [Source?] The source file containing this definition.
|
17
18
|
def initialize(path, parent: nil, language: parent&.language, comments: nil, visibility: :public, source: parent&.source)
|
18
19
|
@path = Array(path).map(&:to_sym)
|
19
20
|
|
@@ -23,6 +24,7 @@ module Decode
|
|
23
24
|
|
24
25
|
@comments = comments
|
25
26
|
@visibility = visibility
|
27
|
+
@documentation = nil
|
26
28
|
|
27
29
|
@full_path = nil
|
28
30
|
@qualified_name = nil
|
@@ -37,9 +39,7 @@ module Decode
|
|
37
39
|
# Generate a string representation of the definition.
|
38
40
|
alias to_s inspect
|
39
41
|
|
40
|
-
# The symbol name.
|
41
|
-
# e.g. `:Decode`.
|
42
|
-
# @attribute [Symbol]
|
42
|
+
# @attribute [Symbol] The symbol name e.g. `:Decode`.
|
43
43
|
def name
|
44
44
|
@path.last
|
45
45
|
end
|
@@ -48,10 +48,11 @@ module Decode
|
|
48
48
|
attr :path
|
49
49
|
|
50
50
|
# The full path to the definition.
|
51
|
+
# @returns [Array(Symbol)] The complete path from root to this definition.
|
51
52
|
def full_path
|
52
53
|
@full_path ||= begin
|
53
|
-
if @parent
|
54
|
-
|
54
|
+
if parent = @parent
|
55
|
+
parent.full_path + @path
|
55
56
|
else
|
56
57
|
@path
|
57
58
|
end
|
@@ -62,56 +63,57 @@ module Decode
|
|
62
63
|
# @returns [Array(Symbol)] The complete path from root to this definition.
|
63
64
|
alias lexical_path full_path
|
64
65
|
|
65
|
-
# @attribute [Definition
|
66
|
+
# @attribute [Definition?] The parent definition, defining lexical scope.
|
66
67
|
attr :parent
|
67
68
|
|
68
69
|
# @attribute [Language::Generic] The language the symbol is defined within.
|
69
70
|
attr :language
|
70
71
|
|
71
|
-
# @attribute [Source
|
72
|
+
# @attribute [Source?] The source file containing this definition.
|
72
73
|
attr :source
|
73
74
|
|
74
|
-
# @attribute [Array(String)] The comment lines which directly preceeded the definition.
|
75
|
+
# @attribute [Array(String)?] The comment lines which directly preceeded the definition.
|
75
76
|
attr :comments
|
76
77
|
|
77
78
|
# Whether the definition is considered part of the public interface.
|
78
79
|
# This is used to determine whether the definition should be documented for coverage purposes.
|
79
|
-
# @returns [
|
80
|
+
# @returns [bool] True if the definition is public.
|
80
81
|
def public?
|
81
82
|
true
|
82
83
|
end
|
83
84
|
|
84
85
|
# Whether the definition has documentation.
|
85
|
-
# @returns [
|
86
|
+
# @returns [bool] True if the definition has non-empty comments.
|
86
87
|
def documented?
|
87
|
-
@comments&.any?
|
88
|
+
@comments&.any? || false
|
88
89
|
end
|
89
90
|
|
90
91
|
# The qualified name is an absolute name which includes any and all namespacing.
|
91
92
|
# @returns [String]
|
92
93
|
def qualified_name
|
93
94
|
@qualified_name ||= begin
|
94
|
-
if @parent
|
95
|
-
[
|
95
|
+
if parent = @parent
|
96
|
+
[parent.qualified_name, self.nested_name].join("::")
|
96
97
|
else
|
97
98
|
self.nested_name
|
98
99
|
end
|
99
100
|
end
|
100
101
|
end
|
101
102
|
|
102
|
-
# The name relative to the parent.
|
103
|
-
# @returns [String]
|
103
|
+
# @returns [String] The name relative to the parent.
|
104
104
|
def nested_name
|
105
105
|
@nested_name ||= "#{@path.join("::")}"
|
106
106
|
end
|
107
107
|
|
108
108
|
# Does the definition name match the specified prefix?
|
109
|
-
# @
|
109
|
+
# @parameter prefix [String] The prefix to match against.
|
110
|
+
# @returns [bool]
|
110
111
|
def start_with?(prefix)
|
111
112
|
self.nested_name.start_with?(prefix)
|
112
113
|
end
|
113
114
|
|
114
115
|
# Convert this definition into another kind of definition.
|
116
|
+
# @parameter kind [Symbol] The kind to convert to.
|
115
117
|
def convert(kind)
|
116
118
|
raise ArgumentError, "Unable to convert #{self} into #{kind}!"
|
117
119
|
end
|
@@ -119,14 +121,14 @@ module Decode
|
|
119
121
|
# A short form of the definition.
|
120
122
|
# e.g. `def short_form`.
|
121
123
|
#
|
122
|
-
# @returns [String
|
124
|
+
# @returns [String?]
|
123
125
|
def short_form
|
124
126
|
end
|
125
127
|
|
126
128
|
# A long form of the definition.
|
127
129
|
# e.g. `def initialize(kind, name, comments, **options)`.
|
128
130
|
#
|
129
|
-
# @returns [String
|
131
|
+
# @returns [String?]
|
130
132
|
def long_form
|
131
133
|
self.short_form
|
132
134
|
end
|
@@ -134,50 +136,50 @@ module Decode
|
|
134
136
|
# A long form which uses the qualified name if possible.
|
135
137
|
# Defaults to {long_form}.
|
136
138
|
#
|
137
|
-
# @returns [String
|
139
|
+
# @returns [String?]
|
138
140
|
def qualified_form
|
139
141
|
self.long_form
|
140
142
|
end
|
141
143
|
|
142
144
|
# Whether the definition spans multiple lines.
|
143
145
|
#
|
144
|
-
# @returns [
|
146
|
+
# @returns [bool]
|
145
147
|
def multiline?
|
146
148
|
false
|
147
149
|
end
|
148
150
|
|
149
151
|
# The full text of the definition.
|
150
152
|
#
|
151
|
-
# @returns [String
|
153
|
+
# @returns [String?]
|
152
154
|
def text
|
153
155
|
end
|
154
156
|
|
155
157
|
# Whether this definition can contain nested definitions.
|
156
158
|
#
|
157
|
-
# @returns [
|
159
|
+
# @returns [bool]
|
158
160
|
def container?
|
159
161
|
false
|
160
162
|
end
|
161
163
|
|
162
164
|
# Whether this represents a single entity to be documented (along with it's contents).
|
163
165
|
#
|
164
|
-
# @returns [
|
166
|
+
# @returns [bool]
|
165
167
|
def nested?
|
166
168
|
container?
|
167
169
|
end
|
168
170
|
|
169
171
|
# Structured access to the definitions comments.
|
170
172
|
#
|
171
|
-
# @returns [Documentation
|
173
|
+
# @returns [Documentation?] A {Documentation} instance if this definition has comments.
|
172
174
|
def documentation
|
173
|
-
if @comments
|
174
|
-
@documentation ||= Documentation.new(
|
175
|
+
if comments = @comments and comments.any?
|
176
|
+
@documentation ||= Documentation.new(comments, @language)
|
175
177
|
end
|
176
178
|
end
|
177
179
|
|
178
180
|
# The location of the definition.
|
179
181
|
#
|
180
|
-
# @returns [Location
|
182
|
+
# @returns [Location?] A {Location} instance if this definition has a location.
|
181
183
|
def location
|
182
184
|
nil
|
183
185
|
end
|
data/lib/decode/documentation.rb
CHANGED
@@ -7,6 +7,7 @@ require_relative "comment/node"
|
|
7
7
|
|
8
8
|
require_relative "comment/tags"
|
9
9
|
require_relative "comment/attribute"
|
10
|
+
require_relative "comment/constant"
|
10
11
|
require_relative "comment/parameter"
|
11
12
|
require_relative "comment/option"
|
12
13
|
require_relative "comment/pragma"
|
@@ -21,20 +22,24 @@ module Decode
|
|
21
22
|
# Initialize the documentation with an array of comments, within a specific language.
|
22
23
|
#
|
23
24
|
# @parameter comments [Array(String)] An array of comment lines.
|
24
|
-
# @parameter language [Language] The language in which the comments were extracted.
|
25
|
-
def initialize(comments, language
|
25
|
+
# @parameter language [Language::Generic?] The language in which the comments were extracted.
|
26
|
+
def initialize(comments, language)
|
27
|
+
super(nil)
|
28
|
+
|
26
29
|
@comments = comments
|
27
30
|
@language = language
|
28
31
|
|
29
|
-
language
|
30
|
-
|
32
|
+
if language
|
33
|
+
language.tags.parse(@comments.dup) do |node|
|
34
|
+
self.add(node)
|
35
|
+
end
|
31
36
|
end
|
32
37
|
end
|
33
38
|
|
34
39
|
# @attribute [Array(String)] The underlying comments from which the documentation is extracted.
|
35
40
|
attr :comments
|
36
41
|
|
37
|
-
# @attribute [Language::Generic] The language in which the documentation was extracted from.
|
42
|
+
# @attribute [Language::Generic?] The language in which the documentation was extracted from.
|
38
43
|
attr :language
|
39
44
|
end
|
40
45
|
end
|
data/lib/decode/index.rb
CHANGED
@@ -11,10 +11,11 @@ require_relative "languages"
|
|
11
11
|
module Decode
|
12
12
|
# Represents a list of definitions organised for quick lookup and lexical enumeration.
|
13
13
|
class Index
|
14
|
-
# Create and populate an index from the given paths.
|
15
|
-
# @parameter paths [Array(String)]
|
14
|
+
# Create and populate an index from the given paths.
|
15
|
+
# @parameter paths [Array(String)] Variable number of paths to index (files, directories, or glob patterns).
|
16
16
|
# @parameter languages [Languages] The languages to support in this index.
|
17
17
|
# @returns [Index] A new index populated with definitions from the given paths.
|
18
|
+
# @rbs (*String, ?languages: Languages) -> Index
|
18
19
|
def self.for(*paths, languages: Languages.all)
|
19
20
|
# Resolve all paths to actual files:
|
20
21
|
resolved_paths = paths.flat_map do |path|
|
@@ -74,7 +75,7 @@ module Decode
|
|
74
75
|
attr :definitions
|
75
76
|
|
76
77
|
# A (prefix) trie of lexically scoped definitions.
|
77
|
-
# @attribute [Trie] The trie structure for efficient lookups.
|
78
|
+
# @attribute [Trie[Definition]] The trie structure for efficient lookups.
|
78
79
|
attr :trie
|
79
80
|
|
80
81
|
# Updates the index by parsing the specified files.
|
@@ -102,12 +103,12 @@ module Decode
|
|
102
103
|
|
103
104
|
# Lookup the specified reference and return matching definitions.
|
104
105
|
# @parameter reference [Language::Reference] The reference to match.
|
105
|
-
# @parameter relative_to [Definition] Lookup the reference relative to the scope of this definition.
|
106
|
-
# @returns [Definition
|
106
|
+
# @parameter relative_to [Definition?] Lookup the reference relative to the scope of this definition.
|
107
|
+
# @returns [Definition?] The best matching definition, or nil if not found.
|
107
108
|
def lookup(reference, relative_to: nil)
|
108
109
|
if reference.absolute? || relative_to.nil?
|
109
110
|
# Start from root scope:
|
110
|
-
lexical_path = []
|
111
|
+
lexical_path = [] #: Array[Symbol]
|
111
112
|
else
|
112
113
|
# Start from the given definition's scope:
|
113
114
|
lexical_path = relative_to.full_path.dup
|
@@ -122,7 +123,11 @@ module Decode
|
|
122
123
|
if node.children[path.first]
|
123
124
|
if target = node.lookup(path)
|
124
125
|
# Return the best matching definition:
|
125
|
-
|
126
|
+
if values = target.values
|
127
|
+
return reference.best(values)
|
128
|
+
else
|
129
|
+
return nil
|
130
|
+
end
|
126
131
|
else
|
127
132
|
return nil
|
128
133
|
end
|
@@ -65,7 +65,7 @@ module Decode
|
|
65
65
|
end
|
66
66
|
|
67
67
|
# Get the parser for this language.
|
68
|
-
# @returns [
|
68
|
+
# @returns [untyped] The parser instance, or nil if not available.
|
69
69
|
def parser
|
70
70
|
nil
|
71
71
|
end
|
@@ -92,6 +92,15 @@ module Decode
|
|
92
92
|
parser.segments_for(source, &block)
|
93
93
|
end
|
94
94
|
end
|
95
|
+
|
96
|
+
# Generate a code representation with syntax highlighting and link resolution.
|
97
|
+
# @parameter text [String] The source code text to format.
|
98
|
+
# @parameter index [Index] The index for resolving references.
|
99
|
+
# @parameter relative_to [Definition] The definition to resolve relative references from.
|
100
|
+
# @returns [untyped] A formatted code object with syntax highlighting.
|
101
|
+
def code_for(text, index, relative_to: nil)
|
102
|
+
raise NotImplementedError, "Code generation is not implemented for #{self.class}!"
|
103
|
+
end
|
95
104
|
end
|
96
105
|
end
|
97
106
|
end
|
@@ -9,6 +9,8 @@ module Decode
|
|
9
9
|
class Reference
|
10
10
|
# Initialize the reference.
|
11
11
|
# @parameter identifier [String] The identifier part of the reference.
|
12
|
+
# @parameter language [Language::Generic] The language this reference belongs to.
|
13
|
+
# @parameter lexical_path [Array(String)?] The lexical path scope for resolution.
|
12
14
|
def initialize(identifier, language, lexical_path = nil)
|
13
15
|
@identifier = identifier
|
14
16
|
@language = language
|
@@ -70,12 +72,13 @@ module Decode
|
|
70
72
|
end
|
71
73
|
|
72
74
|
# Find the best matching definition from a list.
|
73
|
-
# @parameter definitions [Array(
|
75
|
+
# @parameter definitions [Array(Definition)] The definitions to choose from.
|
76
|
+
# @returns [Definition?] The best matching definition, if any.
|
74
77
|
def best(definitions)
|
75
78
|
prefix, name = lexical_path.last
|
76
79
|
|
77
|
-
first = nil
|
78
|
-
without_prefix = nil
|
80
|
+
first = nil #: Definition?
|
81
|
+
without_prefix = nil #: Definition?
|
79
82
|
|
80
83
|
definitions.each do |definition|
|
81
84
|
first ||= definition
|
@@ -93,7 +96,7 @@ module Decode
|
|
93
96
|
end
|
94
97
|
|
95
98
|
# The lexical path of the reference.
|
96
|
-
# @returns [Array(
|
99
|
+
# @returns [Array(Symbol)]
|
97
100
|
def path
|
98
101
|
@path ||= self.lexical_path.map{|_, name| name.to_sym}
|
99
102
|
end
|
@@ -58,13 +58,13 @@ module Decode
|
|
58
58
|
end
|
59
59
|
|
60
60
|
# A singleton class is a container for other definitions.
|
61
|
-
# @returns [
|
61
|
+
# @returns [bool]
|
62
62
|
def container?
|
63
63
|
true
|
64
64
|
end
|
65
65
|
|
66
66
|
# Typically, a singleton class does not contain other definitions.
|
67
|
-
# @returns [
|
67
|
+
# @returns [bool]
|
68
68
|
def nested?
|
69
69
|
false
|
70
70
|
end
|
@@ -16,9 +16,9 @@ module Decode
|
|
16
16
|
# Initialize a new code block.
|
17
17
|
# @parameter text [String] The code text.
|
18
18
|
# @parameter index [Index] The index to use.
|
19
|
-
# @parameter relative_to [Definition] The definition this code is relative to.
|
20
|
-
# @parameter language [Language] The language of the code.
|
21
|
-
def initialize(text, index, relative_to: nil, language:
|
19
|
+
# @parameter relative_to [Definition?] The definition this code is relative to.
|
20
|
+
# @parameter language [Language::Generic] The language of the code.
|
21
|
+
def initialize(text, index, relative_to: nil, language:)
|
22
22
|
@text = text
|
23
23
|
@root = ::Prism.parse(text)
|
24
24
|
@index = index
|
@@ -26,12 +26,24 @@ module Decode
|
|
26
26
|
@language = language
|
27
27
|
end
|
28
28
|
|
29
|
+
# @attribute [String] The code text.
|
29
30
|
attr :text
|
30
31
|
|
32
|
+
# @attribute [untyped] The parsed syntax tree.
|
33
|
+
attr :root
|
34
|
+
|
35
|
+
# @attribute [Index] The index to use for lookups.
|
36
|
+
attr :index
|
37
|
+
|
38
|
+
# @attribute [Definition?] The definition this code is relative to.
|
39
|
+
attr :relative_to
|
40
|
+
|
41
|
+
# @attribute [Language::Generic] The language of the code.
|
31
42
|
attr :language
|
32
43
|
|
33
44
|
# Extract definitions from the code.
|
34
45
|
# @parameter into [Array] The array to extract definitions into.
|
46
|
+
# @returns [Array] The array with extracted definitions.
|
35
47
|
def extract(into = [])
|
36
48
|
if @index
|
37
49
|
traverse(@root.value, into)
|
@@ -42,6 +54,10 @@ module Decode
|
|
42
54
|
|
43
55
|
private
|
44
56
|
|
57
|
+
# Traverse the syntax tree and extract definitions.
|
58
|
+
# @parameter node [untyped] The syntax tree node to traverse.
|
59
|
+
# @parameter into [Array] The array to extract definitions into.
|
60
|
+
# @returns [self]
|
45
61
|
def traverse(node, into)
|
46
62
|
case node&.type
|
47
63
|
when :program_node
|
@@ -75,6 +91,8 @@ module Decode
|
|
75
91
|
traverse(child, into)
|
76
92
|
end
|
77
93
|
end
|
94
|
+
|
95
|
+
return self
|
78
96
|
end
|
79
97
|
end
|
80
98
|
end
|
@@ -31,13 +31,25 @@ module Decode
|
|
31
31
|
attr_accessor :visibility
|
32
32
|
|
33
33
|
# Check if this definition is public.
|
34
|
-
# @returns [
|
34
|
+
# @returns [bool] True if the definition is public.
|
35
35
|
def public?
|
36
36
|
@visibility == :public
|
37
37
|
end
|
38
38
|
|
39
|
+
# Check if this definition is protected.
|
40
|
+
# @returns [bool] True if the definition is protected.
|
41
|
+
def protected?
|
42
|
+
@visibility == :protected
|
43
|
+
end
|
44
|
+
|
45
|
+
# Check if this definition is private.
|
46
|
+
# @returns [bool] True if the definition is private.
|
47
|
+
def private?
|
48
|
+
@visibility == :private
|
49
|
+
end
|
50
|
+
|
39
51
|
# Check if this definition spans multiple lines.
|
40
|
-
# @returns [
|
52
|
+
# @returns [bool] True if the definition spans multiple lines.
|
41
53
|
def multiline?
|
42
54
|
@node.location.start_line != @node.location.end_line
|
43
55
|
end
|
@@ -63,7 +75,7 @@ module Decode
|
|
63
75
|
end
|
64
76
|
|
65
77
|
# Get the location of this definition.
|
66
|
-
# @returns [Location
|
78
|
+
# @returns [Location?] The location object if source is available.
|
67
79
|
def location
|
68
80
|
if @source and location = @node&.location
|
69
81
|
Location.new(@source.path, location.start_line)
|
@@ -19,6 +19,7 @@ module Decode
|
|
19
19
|
|
20
20
|
TAGS = Comment::Tags.build do |tags|
|
21
21
|
tags["attribute"] = Comment::Attribute
|
22
|
+
tags["constant"] = Comment::Constant
|
22
23
|
tags["parameter"] = Comment::Parameter
|
23
24
|
tags["option"] = Comment::Option
|
24
25
|
tags["yields"] = Comment::Yields
|
@@ -37,7 +38,7 @@ module Decode
|
|
37
38
|
end
|
38
39
|
|
39
40
|
# Get the parser for Ruby source code.
|
40
|
-
# @returns [Parser] The Ruby parser instance.
|
41
|
+
# @returns [Language::Ruby::Parser] The Ruby parser instance.
|
41
42
|
def parser
|
42
43
|
@parser ||= Parser.new(self)
|
43
44
|
end
|