yard_to_rbs_inline 0.1.1 → 0.3.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/.rubocop.yml +32 -1
- data/CHANGELOG.md +3 -0
- data/README.md +14 -4
- data/Rakefile +39 -1
- data/Steepfile +36 -0
- data/examples/example-converted.rb +30 -0
- data/examples/example.rb +2 -0
- data/exe/yard_to_rbs_inline +6 -0
- data/lib/yard_to_rbs_inline/cli.rb +2 -0
- data/lib/yard_to_rbs_inline/converter/code_visitor.rb +103 -76
- data/lib/yard_to_rbs_inline/converter/subscriptable.rb +20 -8
- data/lib/yard_to_rbs_inline/converter/text_with_mod.rb +27 -15
- data/lib/yard_to_rbs_inline/converter.rb +4 -2
- data/lib/yard_to_rbs_inline/version.rb +1 -1
- data/lib/yard_to_rbs_inline/yard_type/ast.rb +15 -8
- data/lib/yard_to_rbs_inline/yard_type/parser.rb +10 -12
- data/lib/yard_to_rbs_inline/yard_type/parser.y +8 -10
- data/lib/yard_to_rbs_inline/yard_type/scanner.rb +55 -48
- data/lib/yard_to_rbs_inline/yard_type.rb +5 -3
- data/rbs_collection.yaml +19 -0
- data/sig/yard_to_rbs_inline_example.rbs +0 -1
- data/types/gems/racc.rbs +4 -0
- metadata +10 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86fdbb3d79a0b8fc087b0c561fde8b42a177d16354dc58dc44aa45df1c907c20
|
4
|
+
data.tar.gz: ecc100f64d44a665156193acba142037010703c9b11b943fa3868cad5f42a6ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54d0d43ce951c23222a3eafc0164f24b15336dcc2e9bb7e707747c1f4d116a6a0cef87902a85ee2a31707a3bea7d4431717d3ff7b9e280115add7a7409e74362
|
7
|
+
data.tar.gz: 0ed86dd791e4806b68114796b1ccd26d66ca127923e0d99c6a3a323243c418aadaa99bd1ad6ff645c405fa8d4f522435158daa0b73d210be5ea4f298c7281208
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,29 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rbs_inline
|
3
|
+
|
1
4
|
AllCops:
|
2
|
-
TargetRubyVersion: 2
|
5
|
+
TargetRubyVersion: 3.2
|
6
|
+
Exclude:
|
7
|
+
- lib/yard_to_rbs_inline/yard_type/parser.rb # Generated file by racc
|
8
|
+
|
9
|
+
Lint/MissingSuper:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Lint/NonLocalExitFromIterator:
|
13
|
+
Enabled: false
|
14
|
+
|
15
|
+
Lint/ShadowingOuterLocalVariable:
|
16
|
+
Enabled: false
|
17
|
+
|
18
|
+
Naming/FileName:
|
19
|
+
Exclude:
|
20
|
+
- examples/**
|
21
|
+
|
22
|
+
Style/Documentation:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/StringConcatenation:
|
26
|
+
Mode: conservative
|
3
27
|
|
4
28
|
Style/StringLiterals:
|
5
29
|
Enabled: true
|
@@ -9,5 +33,12 @@ Style/StringLiteralsInInterpolation:
|
|
9
33
|
Enabled: true
|
10
34
|
EnforcedStyle: double_quotes
|
11
35
|
|
36
|
+
Layout/LeadingCommentSpace:
|
37
|
+
AllowRBSInlineAnnotation: true
|
38
|
+
AllowSteepAnnotation: true
|
39
|
+
|
12
40
|
Layout/LineLength:
|
13
41
|
Max: 120
|
42
|
+
|
43
|
+
Metrics:
|
44
|
+
Enabled: false
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,15 +1,25 @@
|
|
1
1
|
# yard → rbs-inline
|
2
2
|
|
3
|
-
|
3
|
+
Insert [rbs-inline](https://github.com/soutaro/rbs-inline) comments from [YARD type annotations](https://yardoc.org/types.html) in your codes.
|
4
4
|
|
5
5
|
## Usage
|
6
6
|
|
7
|
+
Install this gem with the following command.
|
8
|
+
|
7
9
|
```console
|
8
|
-
|
10
|
+
gem install yard_to_rbs_inline
|
11
|
+
```
|
12
|
+
|
13
|
+
Then, run the following command to insert rbs-inline comments to your codes.
|
9
14
|
|
15
|
+
```console
|
10
16
|
# Print rewrited code to stdout.
|
11
|
-
|
17
|
+
yard_to_rbs_inline --dry-run your-file.rb
|
12
18
|
|
13
19
|
# Overwrite files.
|
14
|
-
|
20
|
+
yard_to_rbs_inline your-file.rb
|
15
21
|
```
|
22
|
+
|
23
|
+
## Examples
|
24
|
+
|
25
|
+
See: [examples](./examples)
|
data/Rakefile
CHANGED
@@ -10,13 +10,51 @@ require "bump/tasks"
|
|
10
10
|
|
11
11
|
RuboCop::RakeTask.new
|
12
12
|
|
13
|
-
task default: %i[spec rubocop]
|
13
|
+
task default: %i[spec rubocop steep]
|
14
14
|
|
15
15
|
desc "Build parser files generated by racc"
|
16
16
|
task racc: [
|
17
17
|
"lib/yard_to_rbs_inline/yard_type/parser.rb"
|
18
18
|
]
|
19
19
|
|
20
|
+
desc "Build rbs files"
|
21
|
+
task rbs: ["rbs:collection", "rbs:inline"]
|
22
|
+
|
23
|
+
namespace :rbs do
|
24
|
+
desc "Install collections"
|
25
|
+
task :collection do
|
26
|
+
sh "bundle exec rbs collection install"
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Generate RBS files"
|
30
|
+
task inline: "rbs:inline:build"
|
31
|
+
|
32
|
+
namespace :inline do
|
33
|
+
desc "Generate RBS files from rbs-inline"
|
34
|
+
task :build do
|
35
|
+
sh "bundle exec rbs-inline lib --opt-out --output=sig/inline"
|
36
|
+
end
|
37
|
+
|
38
|
+
desc "Watch files to build rbs-inline"
|
39
|
+
task :watch do
|
40
|
+
require "listen"
|
41
|
+
|
42
|
+
listener = Listen.to("lib", only: /\.rb$/) do
|
43
|
+
Rake::Task["rbs:inline:build"].execute
|
44
|
+
end
|
45
|
+
listener.start
|
46
|
+
sleep
|
47
|
+
ensure
|
48
|
+
listener&.stop
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
desc "Type check the code"
|
54
|
+
task steep: ["rbs:collection", "rbs:inline"] do
|
55
|
+
sh "bundle exec steep check"
|
56
|
+
end
|
57
|
+
|
20
58
|
rule ".rb" => ".y" do |t|
|
21
59
|
sh "bundle exec racc #{t.source} -o #{t.name}"
|
22
60
|
end
|
data/Steepfile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
D = Steep::Diagnostic
|
4
|
+
|
5
|
+
target :lib do
|
6
|
+
signature "sig"
|
7
|
+
signature "types"
|
8
|
+
ignore_signature "sig/test"
|
9
|
+
|
10
|
+
check "lib" # Directory name
|
11
|
+
# check "path/to/source.rb" # File name
|
12
|
+
# check "app/models/**/*.rb" # Glob
|
13
|
+
ignore "lib/yard_to_rbs_inline/yard_type/parser.rb" # Ignore generated files
|
14
|
+
# ignore "lib/templates/*.rb"
|
15
|
+
|
16
|
+
# library "pathname" # Standard libraries
|
17
|
+
# library "strong_json" # Gems
|
18
|
+
|
19
|
+
# configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
|
20
|
+
# configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
|
21
|
+
# configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
|
22
|
+
# configure_code_diagnostics(D::Ruby.silent) # `silent` diagnostics setting
|
23
|
+
# configure_code_diagnostics do |hash| # You can setup everything yourself
|
24
|
+
# hash[D::Ruby::NoMethod] = :information
|
25
|
+
# end
|
26
|
+
end
|
27
|
+
|
28
|
+
# target :test do
|
29
|
+
# unreferenced! # Skip type checking the `lib` code when types in `test` target is changed
|
30
|
+
# signature "sig/test" # Put RBS files for tests under `sig/test`
|
31
|
+
# check "test" # Type check Ruby scripts under `test`
|
32
|
+
#
|
33
|
+
# configure_code_diagnostics(D::Ruby.lenient) # Weak type checking for test code
|
34
|
+
#
|
35
|
+
# # library "pathname" # Standard libraries
|
36
|
+
# end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rbs_inline: enabled
|
4
|
+
|
5
|
+
class Code
|
6
|
+
# @return [String]
|
7
|
+
attr_reader :source #: String
|
8
|
+
|
9
|
+
# @param source [String]
|
10
|
+
#: (String source) -> untyped
|
11
|
+
def initialize(source)
|
12
|
+
@source = source
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param new_source [String]
|
16
|
+
# @return [Code]
|
17
|
+
#: (String new_source) -> Code
|
18
|
+
def rewrite(new_source)
|
19
|
+
@source = new_source
|
20
|
+
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param recover [Boolean].
|
25
|
+
# @return [Array<Token>]
|
26
|
+
#: (?recover: bool) -> Array[Token]
|
27
|
+
def tokenize(recover: false)
|
28
|
+
parser.tokenize(source, recover: recover)
|
29
|
+
end
|
30
|
+
end
|
data/examples/example.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# rbs_inline: enabled
|
2
4
|
|
3
|
-
require_relative
|
5
|
+
require_relative "subscriptable"
|
4
6
|
|
5
7
|
module YardToRbsInline
|
6
8
|
module Converter
|
@@ -10,20 +12,23 @@ module YardToRbsInline
|
|
10
12
|
# @!rbs
|
11
13
|
# type mod = PrependLine | AppendLineContent
|
12
14
|
|
13
|
-
|
15
|
+
# @rbs @source: Prism::Source
|
16
|
+
attr_reader :source #: Prism::Source
|
14
17
|
|
15
|
-
|
18
|
+
# @rbs @comments: Array[Prism::comment]
|
19
|
+
attr_reader :comments #: Array[Prism::comment]
|
16
20
|
|
17
|
-
|
21
|
+
# @rbs @text_with_mod: TextWithMod
|
22
|
+
attr_reader :text_with_mod #: TextWithMod
|
18
23
|
|
19
|
-
|
24
|
+
#: (source: Prism::Source, comments: Array[Prism::comment]) -> untyped
|
20
25
|
def initialize(source:, comments:)
|
21
26
|
@source = source
|
22
27
|
@comments = comments
|
23
28
|
@text_with_mod = TextWithMod.new(source.source)
|
24
29
|
end
|
25
30
|
|
26
|
-
|
31
|
+
#: (Prism::CallNode) -> void
|
27
32
|
def visit_call_node(node)
|
28
33
|
parse_annotation = lambda do
|
29
34
|
annotation_comments = annotations_for(node)
|
@@ -35,29 +40,29 @@ module YardToRbsInline
|
|
35
40
|
when :attr_reader
|
36
41
|
annotation = parse_annotation.call
|
37
42
|
|
38
|
-
unless annotation.match?(/^\s*#(
|
39
|
-
docstring = YARD::DocstringParser.new.parse(annotation.gsub(/^\s*#\s*/,
|
43
|
+
unless annotation.match?(/^\s*#(:|\s*@rbs)/)
|
44
|
+
docstring = YARD::DocstringParser.new.parse(annotation.gsub(/^\s*#\s*/, "")).to_docstring
|
40
45
|
|
41
46
|
sig = capture_error_to_write_comment(node) { build_return_sig(docstring) }
|
42
|
-
text_with_mod.mods << AppendLineContent.from_node_and_content(node, "
|
47
|
+
text_with_mod.mods << AppendLineContent.from_node_and_content(node, "#: #{sig}")
|
43
48
|
end
|
44
49
|
end
|
45
50
|
|
46
51
|
super
|
47
52
|
end
|
48
53
|
|
49
|
-
|
54
|
+
#: (Prism::DefNode) -> void
|
50
55
|
def visit_def_node(node)
|
51
56
|
annotation_comments = annotations_for(node)
|
52
57
|
annotation_strs = annotation_comments.map(&method(:source_for_comment))
|
53
58
|
annotation = annotation_strs.map(&:chomp).join("\n")
|
54
59
|
|
55
|
-
unless annotation.match?(/^\s*#(
|
56
|
-
docstring = YARD::DocstringParser.new.parse(annotation.gsub(/^\s*#\s*/,
|
60
|
+
unless annotation.match?(/^\s*#(:|\s*@rbs)/)
|
61
|
+
docstring = YARD::DocstringParser.new.parse(annotation.gsub(/^\s*#\s*/, "")).to_docstring
|
57
62
|
|
58
63
|
sig = capture_error_to_write_comment(node) { build_signature(node.parameters, docstring) }
|
59
64
|
|
60
|
-
text_with_mod.mods << PrependLine.from_node_and_content(node, "
|
65
|
+
text_with_mod.mods << PrependLine.from_node_and_content(node, "#: #{sig}")
|
61
66
|
|
62
67
|
# STDERR.puts "#{node.name_loc.inspect} #{node.name}: #{sig}"
|
63
68
|
end
|
@@ -67,18 +72,18 @@ module YardToRbsInline
|
|
67
72
|
|
68
73
|
private
|
69
74
|
|
70
|
-
|
75
|
+
#: (YARD::Docstring) -> String
|
71
76
|
def build_return_sig(docstring)
|
72
|
-
return_tag = docstring.tag("return")
|
77
|
+
return_tag = docstring.tag("return") #: YARD::Tags::Tag | nil
|
73
78
|
|
74
|
-
if return_tag&.types
|
75
|
-
convert_types(
|
79
|
+
if (types = return_tag&.types)
|
80
|
+
convert_types(types)
|
76
81
|
else
|
77
82
|
"untyped"
|
78
83
|
end
|
79
84
|
end
|
80
85
|
|
81
|
-
|
86
|
+
#: (Prism::ParametersNode | nil, YARD::Docstring) -> String
|
82
87
|
def build_signature(params, docstring)
|
83
88
|
params_sig = build_params_signature(params, docstring)
|
84
89
|
return_sig = build_return_sig(docstring)
|
@@ -86,59 +91,61 @@ module YardToRbsInline
|
|
86
91
|
"(#{params_sig}) -> #{return_sig}"
|
87
92
|
end
|
88
93
|
|
89
|
-
|
94
|
+
#: (Prism::ParametersNode | nil, YARD::Docstring) -> String
|
90
95
|
def build_params_signature(params, docstring)
|
91
96
|
return "" unless params
|
92
97
|
|
93
|
-
param_tags = docstring.tags("param")
|
98
|
+
param_tags = docstring.tags("param") #: Array[YARD::Tags::Tag]
|
94
99
|
|
95
100
|
find_tag = proc do |name|
|
96
|
-
if name
|
97
|
-
param_tags.find { |tag| tag.name == name.to_s }
|
98
|
-
else
|
99
|
-
nil
|
100
|
-
end
|
101
|
+
param_tags.find { |tag| tag.name == name.to_s } if name
|
101
102
|
end
|
102
103
|
|
103
|
-
param_sigs = []
|
104
|
+
param_sigs = [] #: Array[String]
|
104
105
|
params.requireds.each do |param|
|
106
|
+
param = TypeUtils.narrow_with_name(param)
|
107
|
+
next unless param
|
108
|
+
|
105
109
|
tag = find_tag.call(param.name)
|
106
110
|
|
107
|
-
if tag&.types
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
111
|
+
param_sigs << if tag&.types
|
112
|
+
"#{convert_types(tag.types)} #{param.name}"
|
113
|
+
else
|
114
|
+
"untyped #{param.name}"
|
115
|
+
end
|
112
116
|
end
|
113
117
|
|
114
118
|
params.optionals.each do |param|
|
115
119
|
tag = find_tag.call(param.name)
|
116
120
|
|
117
|
-
if tag&.types
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
121
|
+
param_sigs << if tag&.types
|
122
|
+
"?#{convert_types(tag.types)} #{param.name}"
|
123
|
+
else
|
124
|
+
"?untyped #{param.name}"
|
125
|
+
end
|
122
126
|
end
|
123
127
|
|
124
|
-
if (param = params.rest)
|
128
|
+
if (param = TypeUtils.narrow_with_name(params.rest))
|
125
129
|
tag = find_tag.call(param.name)
|
126
130
|
|
127
|
-
if tag&.types
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
131
|
+
param_sigs << if tag&.types
|
132
|
+
"*#{convert_types(tag.types)} #{param.name}"
|
133
|
+
else
|
134
|
+
"*untyped #{param.name}"
|
135
|
+
end
|
132
136
|
end
|
133
137
|
|
134
138
|
params.posts.each do |param|
|
139
|
+
param = TypeUtils.narrow_with_name(param)
|
140
|
+
next unless param
|
141
|
+
|
135
142
|
tag = find_tag.call(param.name)
|
136
143
|
|
137
|
-
if tag&.types
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
144
|
+
param_sigs << if tag&.types
|
145
|
+
"#{convert_types(tag.types)} #{param.name}"
|
146
|
+
else
|
147
|
+
"untyped #{param.name}"
|
148
|
+
end
|
142
149
|
end
|
143
150
|
|
144
151
|
params.keywords.each do |param|
|
@@ -152,43 +159,44 @@ module YardToRbsInline
|
|
152
159
|
"?"
|
153
160
|
end
|
154
161
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
162
|
+
param_sigs << if tag&.types
|
163
|
+
"#{prefix}#{param.name}: #{convert_types(tag.types)}"
|
164
|
+
else
|
165
|
+
"#{prefix}#{param.name}: untyped"
|
166
|
+
end
|
160
167
|
end
|
161
168
|
|
162
|
-
if (param = params.keyword_rest)
|
169
|
+
if (param = TypeUtils.narrow_with_name(params.keyword_rest))
|
170
|
+
|
163
171
|
tag = find_tag.call(param.name)
|
164
172
|
|
165
|
-
if tag&.types
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
173
|
+
param_sigs << if tag&.types
|
174
|
+
"**#{convert_types(tag.types)} #{param.name}"
|
175
|
+
else
|
176
|
+
"**untyped #{param.name}"
|
177
|
+
end
|
170
178
|
end
|
171
179
|
|
172
180
|
# Remove trailing spaces for unnamed params
|
173
181
|
param_sigs.map(&:strip).join(", ")
|
174
182
|
end
|
175
183
|
|
176
|
-
|
184
|
+
#: (Array[String]) -> String
|
177
185
|
def convert_types(yard_type_literals)
|
178
186
|
new_types = yard_type_literals.map do |literal|
|
179
187
|
yard_type = YardToRbsInline::YardType::Parser.new.parse(literal)
|
180
188
|
convert_yard_type(yard_type)
|
181
|
-
rescue Racc::ParseError,
|
189
|
+
rescue Racc::ParseError, YardType::Scanner::ScanError => e
|
182
190
|
# STDERR.puts "Cannot parse #{literal}: #{e}"
|
183
191
|
emit_error_message("Cannot parse #{literal}: #{e}")
|
184
192
|
|
185
|
-
|
193
|
+
"untyped"
|
186
194
|
end.uniq
|
187
195
|
|
188
|
-
new_types.empty? ?
|
196
|
+
new_types.empty? ? "untyped" : new_types.join(" | ")
|
189
197
|
end
|
190
198
|
|
191
|
-
|
199
|
+
#: (YardToRbsInline::YardType::Ast::node) -> String
|
192
200
|
def convert_yard_type(yard_type)
|
193
201
|
case yard_type
|
194
202
|
in YardType::Ast::Type(name:)
|
@@ -212,19 +220,19 @@ module YardToRbsInline
|
|
212
220
|
content
|
213
221
|
in YardType::Ast::GenericType(container_type:, types:)
|
214
222
|
container_sig = container_type ? convert_yard_type(container_type) : "Array"
|
215
|
-
"#{container_sig}[#{types.map(&method(:convert_yard_type)).join(
|
223
|
+
"#{container_sig}[#{types.map(&method(:convert_yard_type)).join(" | ")}]"
|
216
224
|
in YardType::Ast::TupleType(container_type:, types:)
|
217
225
|
container_sig = container_type ? convert_yard_type(container_type) : "Array"
|
218
|
-
"#{container_sig} & [#{types.map(&method(:convert_yard_type)).join(
|
226
|
+
"#{container_sig} & [#{types.map(&method(:convert_yard_type)).join(", ")}]"
|
219
227
|
in YardType::Ast::HashType(container_type:, type_pair: [key_type, value_type])
|
220
228
|
container_sig = container_type ? convert_yard_type(container_type) : "Hash"
|
221
229
|
"#{container_sig}[#{convert_yard_type(key_type)}, #{convert_yard_type(value_type)}]"
|
222
230
|
in YardType::Ast::UnionType(types:)
|
223
|
-
types.map(&method(:convert_yard_type)).join(
|
231
|
+
types.map(&method(:convert_yard_type)).join(" | ")
|
224
232
|
end
|
225
233
|
end
|
226
234
|
|
227
|
-
|
235
|
+
#: (Prism::Node) -> Integer
|
228
236
|
def start_line_of_node(node)
|
229
237
|
gather_comment_targets = proc do |l|
|
230
238
|
if l.respond_to?(:comment_targets)
|
@@ -237,34 +245,53 @@ module YardToRbsInline
|
|
237
245
|
gather_comment_targets.call(node).map(&:start_line).min || 0
|
238
246
|
end
|
239
247
|
|
240
|
-
|
248
|
+
#: (Prism::Node) -> Array[Prism::comment]
|
241
249
|
def annotations_for(node)
|
242
250
|
start_line = start_line_of_node(node)
|
243
251
|
|
244
|
-
matched_comments = []
|
252
|
+
matched_comments = [] #: Array[Prism::comment]
|
245
253
|
matched_comments += comments_by_line[start_line] if comments_by_line[start_line]
|
246
254
|
|
247
255
|
(start_line - 1).downto(1) do |line|
|
248
256
|
current_comments = comments_by_line[line]
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
break
|
253
|
-
end
|
257
|
+
break unless current_comments
|
258
|
+
|
259
|
+
matched_comments += current_comments
|
254
260
|
end
|
255
261
|
|
256
262
|
matched_comments
|
257
263
|
end
|
258
264
|
|
259
|
-
|
265
|
+
#: (Prism::comment) -> String
|
260
266
|
def source_for_comment(comment)
|
261
267
|
source.slice(comment.location.start_offset, comment.location.length)
|
262
268
|
end
|
263
269
|
|
264
|
-
|
270
|
+
# @rbs @comments_by_line: Hash[Integer, Array[Prism::comment]]?
|
271
|
+
|
272
|
+
#: () -> Hash[Integer, Array[Prism::comment]]
|
265
273
|
def comments_by_line
|
266
274
|
@comments_by_line ||= comments.group_by { |comment| comment.location.start_line }
|
267
275
|
end
|
276
|
+
|
277
|
+
module TypeUtils
|
278
|
+
module_function
|
279
|
+
|
280
|
+
# @rbs!
|
281
|
+
# interface _WithName
|
282
|
+
# def name: () -> String
|
283
|
+
# end
|
284
|
+
|
285
|
+
# @rbs!
|
286
|
+
# interface _RespondTo
|
287
|
+
# def respond_to?: (String | Symbol) -> boolish
|
288
|
+
# end
|
289
|
+
|
290
|
+
#: [T < _RespondTo] (T) -> (T & _WithName)?
|
291
|
+
def narrow_with_name(node)
|
292
|
+
node.respond_to?(:name) && node #: untyped
|
293
|
+
end
|
294
|
+
end
|
268
295
|
end
|
269
296
|
end
|
270
297
|
end
|
@@ -1,33 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# rbs_inline: enabled
|
2
4
|
|
3
5
|
module YardToRbsInline
|
4
6
|
module Converter
|
7
|
+
# @rbs!
|
8
|
+
# interface _TextWithModContainer
|
9
|
+
# def text_with_mod: () -> TextWithMod
|
10
|
+
# end
|
11
|
+
|
12
|
+
# @rbs module-self _TextWithModContainer
|
5
13
|
module Subscriptable
|
6
14
|
# @rbs!
|
7
15
|
# type subscriber = ^(String) -> void
|
8
16
|
|
9
|
-
|
17
|
+
#: (String) -> void
|
10
18
|
def emit_error_message(error_message)
|
11
19
|
(@subscribers || []).each { |subscriber| subscriber.call(error_message) }
|
12
20
|
end
|
13
21
|
|
14
|
-
|
22
|
+
# @rbs @subscribers: Array[subscriber]
|
23
|
+
|
24
|
+
#: [X] (subscriber) { () -> X } -> X
|
15
25
|
def capture_error_message(subscriber)
|
16
|
-
@subscribers ||= []
|
26
|
+
@subscribers ||= [] #: Array[subscriber]
|
17
27
|
@subscribers.push(subscriber)
|
18
28
|
yield
|
19
29
|
ensure
|
20
30
|
@subscribers.pop
|
21
31
|
end
|
22
32
|
|
23
|
-
|
33
|
+
#: (Prism::Node) -> subscriber
|
24
34
|
def subscriber_to_prepend_error(node)
|
25
|
-
lambda { |message|
|
35
|
+
lambda { |message|
|
36
|
+
text_with_mod.mods << PrependLine.from_node_and_content(node, "# YARD to RBS Error: #{message}")
|
37
|
+
}
|
26
38
|
end
|
27
39
|
|
28
|
-
|
29
|
-
def capture_error_to_write_comment(node)
|
30
|
-
capture_error_message(subscriber_to_prepend_error(node))
|
40
|
+
#: [X] (Prism::Node) { () -> X } -> X
|
41
|
+
def capture_error_to_write_comment(node, &block)
|
42
|
+
capture_error_message(subscriber_to_prepend_error(node), &block)
|
31
43
|
end
|
32
44
|
end
|
33
45
|
end
|
@@ -1,43 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# rbs_inline: enabled
|
2
4
|
|
3
5
|
module YardToRbsInline
|
4
6
|
module Converter
|
5
|
-
PrependLine
|
6
|
-
|
7
|
+
class PrependLine < Data.define(:line_num, :content)
|
8
|
+
# @rbs!
|
9
|
+
# def initialize: (line_num: Integer, content: String) -> void
|
10
|
+
# attr_reader line_num: Integer
|
11
|
+
# attr_reader content: String
|
12
|
+
|
13
|
+
#: (Prism::Node, String) -> PrependLine
|
7
14
|
def self.from_node_and_content(node, comment_content)
|
8
15
|
start_line = node.location.start_line
|
9
16
|
start_column = node.location.start_column
|
10
17
|
|
11
|
-
line =
|
18
|
+
line = " " * start_column + comment_content
|
12
19
|
|
13
20
|
PrependLine.new(line_num: start_line, content: line)
|
14
21
|
end
|
15
22
|
end
|
16
23
|
|
17
|
-
AppendLineContent
|
18
|
-
|
24
|
+
class AppendLineContent < Data.define(:line_num, :content)
|
25
|
+
# @rbs!
|
26
|
+
# def initialize: (line_num: Integer, content: String) -> void
|
27
|
+
# attr_reader line_num: Integer
|
28
|
+
# attr_reader content: String
|
29
|
+
|
30
|
+
#: (Prism::Node, String) -> AppendLineContent
|
19
31
|
def self.from_node_and_content(node, comment_content)
|
20
32
|
start_line = node.location.start_line
|
21
33
|
|
22
|
-
AppendLineContent.new(line_num: start_line, content:
|
34
|
+
AppendLineContent.new(line_num: start_line, content: " #{comment_content}")
|
23
35
|
end
|
24
36
|
end
|
25
37
|
|
38
|
+
# @rbs!
|
39
|
+
# type mod = PrependLine | AppendLineContent
|
40
|
+
|
26
41
|
class TextWithMod
|
27
|
-
attr_reader :original_text
|
42
|
+
attr_reader :original_text #: Prism::Source
|
28
43
|
|
29
|
-
attr_reader :mods
|
44
|
+
attr_reader :mods #: Array[mod]
|
30
45
|
|
31
|
-
|
46
|
+
#: (String) -> untyped
|
32
47
|
def initialize(original_text)
|
33
48
|
@original_text = original_text
|
34
49
|
@mods = []
|
35
50
|
end
|
36
51
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
mods.reduce(original_text.lines(chomp: true)) do |source_lines, mod|
|
52
|
+
def modified_text #: String
|
53
|
+
prepended_line_nums = [] #: Array[String]
|
54
|
+
mods.each_with_object(original_text.lines.map(&:chomp)) do |mod, source_lines|
|
41
55
|
real_line_num = mod.line_num + prepended_line_nums.map { |i| i <= mod.line_num }.length # 1-index
|
42
56
|
|
43
57
|
case mod
|
@@ -47,8 +61,6 @@ module YardToRbsInline
|
|
47
61
|
in AppendLineContent(content:)
|
48
62
|
source_lines[real_line_num - 1] += content
|
49
63
|
end
|
50
|
-
|
51
|
-
source_lines
|
52
64
|
end.join("\n") + "\n"
|
53
65
|
end
|
54
66
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# rbs_inline: enabled
|
2
4
|
|
3
5
|
module YardToRbsInline
|
@@ -6,14 +8,19 @@ module YardToRbsInline
|
|
6
8
|
# @rbs!
|
7
9
|
# type node = Type | LiteralType | DuckType | GenericType | TupleType | HashType | UnionType
|
8
10
|
|
9
|
-
Type =
|
10
|
-
LiteralType =
|
11
|
-
DuckType =
|
12
|
-
GenericType =
|
13
|
-
TupleType =
|
14
|
-
HashType =
|
15
|
-
|
16
|
-
|
11
|
+
Type = Data.define(:name)
|
12
|
+
LiteralType = Data.define(:content)
|
13
|
+
DuckType = Data.define(:name)
|
14
|
+
GenericType = Data.define(:container_type, :types)
|
15
|
+
TupleType = Data.define(:container_type, :types)
|
16
|
+
HashType = Data.define(:container_type, :type_pair)
|
17
|
+
|
18
|
+
class UnionType < Data.define(:types)
|
19
|
+
# @rbs!
|
20
|
+
# def initialize: (types: Array[node]) -> void
|
21
|
+
# attr_reader types: Array[node]
|
22
|
+
|
23
|
+
#: (untyped types) -> untyped
|
17
24
|
def self.build(types)
|
18
25
|
if types.length == 1
|
19
26
|
types.first
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
2
|
# DO NOT MODIFY!!!!
|
3
|
-
# This file is automatically generated by Racc 1.
|
4
|
-
# from Racc grammar file "".
|
3
|
+
# This file is automatically generated by Racc 1.8.1
|
4
|
+
# from Racc grammar file "parser.y".
|
5
5
|
#
|
6
6
|
|
7
7
|
require 'racc/parser.rb'
|
@@ -14,14 +14,14 @@ module YardToRbsInline
|
|
14
14
|
|
15
15
|
module_eval(<<'...end parser.y/module_eval...', 'parser.y', 34)
|
16
16
|
|
17
|
-
|
17
|
+
#: (String) -> Ast::node
|
18
18
|
def parse(string)
|
19
19
|
@tokens = Scanner.new(string).to_racc_tokens
|
20
20
|
|
21
21
|
do_parse()
|
22
22
|
end
|
23
23
|
|
24
|
-
|
24
|
+
#: () -> untyped
|
25
25
|
def next_token
|
26
26
|
@tokens.shift
|
27
27
|
end
|
@@ -294,14 +294,12 @@ end
|
|
294
294
|
end # module YardToRbsInline
|
295
295
|
|
296
296
|
|
297
|
-
module
|
298
|
-
module
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
# def next_token: () -> untyped
|
304
|
-
end
|
297
|
+
module YardToRbsInline
|
298
|
+
module YardType
|
299
|
+
class Parser
|
300
|
+
# @rbs!
|
301
|
+
# def parse: (String) -> Ast::node
|
302
|
+
# def next_token: () -> untyped
|
305
303
|
end
|
306
304
|
end
|
307
305
|
end
|
@@ -32,28 +32,26 @@ end
|
|
32
32
|
|
33
33
|
---- inner
|
34
34
|
|
35
|
-
|
35
|
+
#: (String) -> Ast::node
|
36
36
|
def parse(string)
|
37
37
|
@tokens = Scanner.new(string).to_racc_tokens
|
38
38
|
|
39
39
|
do_parse()
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
#: () -> untyped
|
43
43
|
def next_token
|
44
44
|
@tokens.shift
|
45
45
|
end
|
46
46
|
|
47
47
|
---- footer
|
48
48
|
|
49
|
-
module
|
50
|
-
module
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
# def next_token: () -> untyped
|
56
|
-
end
|
49
|
+
module YardToRbsInline
|
50
|
+
module YardType
|
51
|
+
class Parser
|
52
|
+
# @rbs!
|
53
|
+
# def parse: (String) -> Ast::node
|
54
|
+
# def next_token: () -> untyped
|
57
55
|
end
|
58
56
|
end
|
59
57
|
end
|
@@ -1,69 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# rbs_inline: enabled
|
2
4
|
|
3
|
-
require
|
5
|
+
require "strscan"
|
4
6
|
|
5
|
-
module YardToRbsInline
|
6
|
-
|
7
|
-
class
|
7
|
+
module YardToRbsInline
|
8
|
+
module YardType
|
9
|
+
class Scanner
|
10
|
+
class ScanError < StandardError; end
|
8
11
|
|
9
|
-
|
12
|
+
Token = Struct.new(:kind, :content, keyword_init: true)
|
10
13
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
14
|
+
TOKEN_PATTERNS = {
|
15
|
+
generic_start: /</,
|
16
|
+
generic_end: />/,
|
17
|
+
tuple_start: /\(/,
|
18
|
+
tuple_end: /\)/,
|
19
|
+
duck_symbol: /#/,
|
20
|
+
separator: /[,;]/,
|
21
|
+
arrow: /=>/,
|
22
|
+
hash_start: /\{/,
|
23
|
+
hash_end: /\}/,
|
24
|
+
name: /(::|\w)+/,
|
25
|
+
symbol: /:\w+/,
|
26
|
+
string: [/"[^"]*"/, /'[^']*'/],
|
27
|
+
integer: /\d+/,
|
28
|
+
spaces: /\s+/
|
29
|
+
}.freeze
|
27
30
|
|
28
|
-
|
31
|
+
attr_reader :text #: String
|
29
32
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
33
|
+
#: (String text) -> untyped
|
34
|
+
def initialize(text)
|
35
|
+
@text = text
|
36
|
+
end
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
#: () -> Array[[Symbol | boolish, String]]
|
39
|
+
def to_racc_tokens
|
40
|
+
tokens.map do |token| #$ [Symbol | bool, String]
|
41
|
+
[token.kind.to_s.upcase.to_sym, token.content]
|
42
|
+
end + [
|
43
|
+
[false, "EOS"] #: [bool, String]
|
44
|
+
]
|
45
|
+
end
|
46
|
+
|
47
|
+
# @rbs @tokens: Array[Token]?
|
39
48
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
49
|
+
#: () -> Array[Token]
|
50
|
+
def tokens
|
51
|
+
@tokens ||= begin
|
52
|
+
scanner = StringScanner.new(text)
|
53
|
+
tokens = [] #: Array[Token]
|
54
|
+
|
55
|
+
scan_step = lambda do
|
56
|
+
TOKEN_PATTERNS.each do |kind, pattern_or_patterns|
|
57
|
+
Array(pattern_or_patterns).each do |pattern|
|
58
|
+
next unless (matched = scanner.scan(pattern))
|
45
59
|
|
46
|
-
scan_step = lambda do
|
47
|
-
TOKEN_PATTERNS.each do |kind, pattern_or_patterns|
|
48
|
-
Array(pattern_or_patterns).each do |pattern|
|
49
|
-
if (matched = scanner.scan(pattern))
|
50
60
|
tokens << Token.new(kind: kind, content: matched) unless kind == :spaces
|
51
|
-
return
|
61
|
+
# For now, steep parse this as a return of the whole method
|
62
|
+
return # steep:ignore
|
52
63
|
end
|
53
64
|
end
|
65
|
+
|
66
|
+
raise ScanError, "Unknown keyword #{scanner.rest} (in #{text})"
|
54
67
|
end
|
55
68
|
|
56
|
-
|
57
|
-
end
|
69
|
+
scan_step.call until scanner.eos?
|
58
70
|
|
59
|
-
|
60
|
-
scan_step.call
|
71
|
+
tokens
|
61
72
|
end
|
62
|
-
|
63
|
-
tokens
|
64
73
|
end
|
65
74
|
end
|
66
75
|
end
|
67
|
-
|
68
|
-
|
69
76
|
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# rbs_inline: enabled
|
2
4
|
|
3
5
|
module YardToRbsInline
|
4
6
|
module YardType
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
7
|
+
require_relative "yard_type/ast"
|
8
|
+
require_relative "yard_type/parser"
|
9
|
+
require_relative "yard_type/scanner"
|
8
10
|
end
|
9
11
|
end
|
data/rbs_collection.yaml
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Download sources
|
2
|
+
sources:
|
3
|
+
- type: git
|
4
|
+
name: ruby/gem_rbs_collection
|
5
|
+
remote: https://github.com/ruby/gem_rbs_collection.git
|
6
|
+
revision: main
|
7
|
+
repo_dir: gems
|
8
|
+
|
9
|
+
# You can specify local directories as sources also.
|
10
|
+
# - type: local
|
11
|
+
# path: path/to/your/local/repository
|
12
|
+
|
13
|
+
# A directory to install the downloaded RBSs
|
14
|
+
path: .gem_rbs_collection
|
15
|
+
|
16
|
+
# gems:
|
17
|
+
# # If you want to avoid installing rbs files for gems, you can specify them here.
|
18
|
+
# - name: GEM_NAME
|
19
|
+
# ignore: true
|
data/types/gems/racc.rbs
ADDED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yard_to_rbs_inline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomoya Chiba
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-04-09 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: yard
|
@@ -24,25 +23,12 @@ dependencies:
|
|
24
23
|
- - ">="
|
25
24
|
- !ruby/object:Gem::Version
|
26
25
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: bump
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
26
|
description: Converter of yard to rbs-inline
|
42
27
|
email:
|
43
28
|
- tomo.asleep@gmail.com
|
44
29
|
executables:
|
45
30
|
- yard-to-rbs-inline
|
31
|
+
- yard_to_rbs_inline
|
46
32
|
extensions: []
|
47
33
|
extra_rdoc_files: []
|
48
34
|
files:
|
@@ -53,8 +39,11 @@ files:
|
|
53
39
|
- LICENSE
|
54
40
|
- README.md
|
55
41
|
- Rakefile
|
42
|
+
- Steepfile
|
43
|
+
- examples/example-converted.rb
|
56
44
|
- examples/example.rb
|
57
45
|
- exe/yard-to-rbs-inline
|
46
|
+
- exe/yard_to_rbs_inline
|
58
47
|
- lib/yard_to_rbs_inline.rb
|
59
48
|
- lib/yard_to_rbs_inline/cli.rb
|
60
49
|
- lib/yard_to_rbs_inline/converter.rb
|
@@ -67,14 +56,15 @@ files:
|
|
67
56
|
- lib/yard_to_rbs_inline/yard_type/parser.rb
|
68
57
|
- lib/yard_to_rbs_inline/yard_type/parser.y
|
69
58
|
- lib/yard_to_rbs_inline/yard_type/scanner.rb
|
59
|
+
- rbs_collection.yaml
|
70
60
|
- sig/yard_to_rbs_inline_example.rbs
|
61
|
+
- types/gems/racc.rbs
|
71
62
|
homepage: https://github.com/tomoasleep/yard_to_rbs_inline
|
72
63
|
licenses: []
|
73
64
|
metadata:
|
74
65
|
homepage_uri: https://github.com/tomoasleep/yard_to_rbs_inline
|
75
66
|
source_code_uri: https://github.com/tomoasleep/yard_to_rbs_inline
|
76
67
|
changelog_uri: https://github.com/tomoasleep/yard_to_rbs_inline/blob/main/CHANGELOG.md
|
77
|
-
post_install_message:
|
78
68
|
rdoc_options: []
|
79
69
|
require_paths:
|
80
70
|
- lib
|
@@ -82,15 +72,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
72
|
requirements:
|
83
73
|
- - ">="
|
84
74
|
- !ruby/object:Gem::Version
|
85
|
-
version: 2.
|
75
|
+
version: 3.2.0
|
86
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
77
|
requirements:
|
88
78
|
- - ">="
|
89
79
|
- !ruby/object:Gem::Version
|
90
80
|
version: '0'
|
91
81
|
requirements: []
|
92
|
-
rubygems_version: 3.
|
93
|
-
signing_key:
|
82
|
+
rubygems_version: 3.6.3
|
94
83
|
specification_version: 4
|
95
84
|
summary: Converter of yard to rbs-inline
|
96
85
|
test_files: []
|