yarbs 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -6
- data/lib/yarbs/annotator.rb +52 -8
- data/lib/yarbs/generator.rb +1 -1
- data/lib/yarbs/type_converter.rb +46 -1
- data/lib/yarbs/version.rb +1 -1
- data/lib/yarbs/writer.rb +21 -0
- data/lib/yarbs.rb +1 -0
- data/sig/yarbs/annotator.rbs +7 -0
- data/sig/yarbs/writer.rbs +11 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad6ad92289f8a7d901231eadb81be04511912ffd65f183d0cd00d4f9d2b9b851
|
|
4
|
+
data.tar.gz: 1cae1aaf74795fef87a77eafd33b32c7a8252dd3c0660032d11c9985213ab965
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dce1a1abee4e2d215abf7fc9ca707c00dc166790d86daa644d2bd43ab29348dade7eda387ada1ac39d0bad428e19f4d19321cf57af465d5490376d06fb02b78d
|
|
7
|
+
data.tar.gz: 84096e966259189840b11c1e7d02d5e2b1cbd29fe429d262e9e8733d0d503505ae92706ac3effcbdaafe6fb903fe152bb69cad59159d979862f7cbd37726451e
|
data/README.md
CHANGED
|
@@ -102,6 +102,8 @@ see:
|
|
|
102
102
|
(`@yieldparam`/`@yieldreturn`), and typing a `Proc`/lambda parameter
|
|
103
103
|
- [docs/classes.md](docs/classes.md) — classes, modules, nesting,
|
|
104
104
|
inheritance, mixins, `attr_*`, constants, and visibility
|
|
105
|
+
- [docs/deprecated.md](docs/deprecated.md) — `@deprecated`, turned into
|
|
106
|
+
`%a{deprecated}` so Steep warns wherever deprecated code is used
|
|
105
107
|
|
|
106
108
|
## Development
|
|
107
109
|
|
|
@@ -114,12 +116,6 @@ for yarbs' own dependencies. From there:
|
|
|
114
116
|
- `bundle exec exe/yarbs "lib/**/*.rb" -o sig` regenerates yarbs' own `sig/`
|
|
115
117
|
from its own docs (it's self-hosting)
|
|
116
118
|
|
|
117
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
118
|
-
To release a new version, update the version number in `version.rb`, and
|
|
119
|
-
then run `bundle exec rake release`, which will create a git tag for the
|
|
120
|
-
version, push git commits and the created tag, and push the `.gem` file to
|
|
121
|
-
[rubygems.org](https://rubygems.org).
|
|
122
|
-
|
|
123
119
|
## Contributing
|
|
124
120
|
|
|
125
121
|
Bug reports and pull requests are welcome on GitHub at
|
data/lib/yarbs/annotator.rb
CHANGED
|
@@ -30,7 +30,10 @@ module Yarbs
|
|
|
30
30
|
case decl
|
|
31
31
|
when RBS::AST::Declarations::Class, RBS::AST::Declarations::Module
|
|
32
32
|
inner_namespace = namespace + [decl.name.to_s]
|
|
33
|
-
decl.update(
|
|
33
|
+
decl.update(
|
|
34
|
+
members: visit_all(decl.members, inner_namespace),
|
|
35
|
+
annotations: with_deprecation(decl.annotations, YARD::Registry.at(inner_namespace.join("::")))
|
|
36
|
+
)
|
|
34
37
|
when RBS::AST::Declarations::Constant
|
|
35
38
|
annotate_constant(decl, namespace)
|
|
36
39
|
when RBS::AST::Members::MethodDefinition
|
|
@@ -47,14 +50,13 @@ module Yarbs
|
|
|
47
50
|
def annotate_constant(decl, namespace)
|
|
48
51
|
yard_object = YARD::Registry.at("#{namespace.join("::")}::#{decl.name}")
|
|
49
52
|
types = return_types_of(yard_object)
|
|
50
|
-
return decl if types.empty?
|
|
51
53
|
|
|
52
54
|
RBS::AST::Declarations::Constant.new(
|
|
53
55
|
name: decl.name,
|
|
54
|
-
type: convert(types),
|
|
56
|
+
type: types.empty? ? decl.type : convert(types),
|
|
55
57
|
location: decl.location,
|
|
56
58
|
comment: decl.comment,
|
|
57
|
-
annotations: decl.annotations
|
|
59
|
+
annotations: with_deprecation(decl.annotations, yard_object)
|
|
58
60
|
)
|
|
59
61
|
end
|
|
60
62
|
|
|
@@ -64,7 +66,7 @@ module Yarbs
|
|
|
64
66
|
return member unless yard_method
|
|
65
67
|
|
|
66
68
|
overloads = member.overloads.map { |overload| annotate_overload(overload, yard_method) }
|
|
67
|
-
member.update(overloads: overloads)
|
|
69
|
+
member.update(overloads: overloads, annotations: with_deprecation(member.annotations, yard_method))
|
|
68
70
|
end
|
|
69
71
|
|
|
70
72
|
def annotate_attribute(member, namespace)
|
|
@@ -75,9 +77,11 @@ module Yarbs
|
|
|
75
77
|
suffix = member.is_a?(RBS::AST::Members::AttrWriter) ? "=" : ""
|
|
76
78
|
yard_attr = YARD::Registry.at("#{namespace.join("::")}#{sep}#{member.name}#{suffix}")
|
|
77
79
|
types = return_types_of(yard_attr)
|
|
78
|
-
return member if types.empty?
|
|
79
80
|
|
|
80
|
-
member.update(
|
|
81
|
+
member.update(
|
|
82
|
+
type: types.empty? ? member.type : convert(types),
|
|
83
|
+
annotations: with_deprecation(member.annotations, yard_attr)
|
|
84
|
+
)
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
def annotate_overload(overload, yard_method)
|
|
@@ -130,7 +134,29 @@ module Yarbs
|
|
|
130
134
|
function
|
|
131
135
|
end
|
|
132
136
|
|
|
133
|
-
|
|
137
|
+
required = block.required && !optional_block?(block, yard_method)
|
|
138
|
+
RBS::Types::Block.new(type: new_function, required: required, self_type: block.self_type)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# `rbs prototype rb` marks an explicit `&block` as required unless the
|
|
142
|
+
# body checks `block_given?` or only uses the block conditionally, so a
|
|
143
|
+
# block that's merely captured or forwarded (`other(&block)`) comes out
|
|
144
|
+
# required. Treat the block as optional when:
|
|
145
|
+
#
|
|
146
|
+
# - its `@param` tag includes `nil` (`@param block [Proc, nil]`), or
|
|
147
|
+
# - the body never `yield`s (the block type is an `UntypedFunction`) and
|
|
148
|
+
# no `@yield`/`@yieldparam`/`@yieldreturn` tag documents a contract
|
|
149
|
+
# for callers to fulfil.
|
|
150
|
+
def optional_block?(block, yard_method)
|
|
151
|
+
block_param = yard_method.parameters.find { |name, _| name.to_s.start_with?("&") }&.first
|
|
152
|
+
return false unless block_param
|
|
153
|
+
|
|
154
|
+
name = block_param.to_s.delete_prefix("&")
|
|
155
|
+
tag = yard_method.tags(:param).find { |param| param.name.to_s.delete_prefix("&") == name }
|
|
156
|
+
return true if tag&.types&.include?("nil")
|
|
157
|
+
|
|
158
|
+
block.type.is_a?(RBS::Types::UntypedFunction) &&
|
|
159
|
+
%i[yield yieldparam yieldreturn].none? { |tag_name| yard_method.has_tag?(tag_name) }
|
|
134
160
|
end
|
|
135
161
|
|
|
136
162
|
def annotate_block_function(function, yield_params, new_return_type)
|
|
@@ -263,6 +289,24 @@ module Yarbs
|
|
|
263
289
|
yard_object.tags(:return).flat_map { |tag| tag.types || [] }
|
|
264
290
|
end
|
|
265
291
|
|
|
292
|
+
# Appends a `%a{deprecated}` annotation when the YARD object has a
|
|
293
|
+
# `@deprecated` tag, which Steep reports as `Ruby::DeprecatedReference`
|
|
294
|
+
# wherever the declaration is used. The tag's text becomes the message
|
|
295
|
+
# (`%a{deprecated: Use #bar instead}`), flattened onto one line since
|
|
296
|
+
# Steep only reads the message up to the first newline.
|
|
297
|
+
def with_deprecation(annotations, yard_object)
|
|
298
|
+
tag = yard_object&.tag(:deprecated)
|
|
299
|
+
return annotations unless tag
|
|
300
|
+
|
|
301
|
+
message = tag.text.to_s.split.join(" ")
|
|
302
|
+
string = message.empty? ? "deprecated" : "deprecated: #{message}"
|
|
303
|
+
# RBS::Writer picks whichever %a delimiter pair doesn't appear in the
|
|
304
|
+
# string, and raises if every one of them does.
|
|
305
|
+
string = "deprecated" if ["}", ")", "]", ">", "|"].all? { |char| string.include?(char) }
|
|
306
|
+
|
|
307
|
+
annotations + [RBS::AST::Annotation.new(string: string, location: nil)]
|
|
308
|
+
end
|
|
309
|
+
|
|
266
310
|
def convert(types)
|
|
267
311
|
TypeConverter.convert(types, strict: @strict)
|
|
268
312
|
end
|
data/lib/yarbs/generator.rb
CHANGED
|
@@ -49,7 +49,7 @@ module Yarbs
|
|
|
49
49
|
|
|
50
50
|
out_path = @output_dir.join(relative_sig_path(file))
|
|
51
51
|
out_path.dirname.mkpath
|
|
52
|
-
out_path.open("w") { |io|
|
|
52
|
+
out_path.open("w") { |io| Writer.new(out: io).write(annotated) }
|
|
53
53
|
|
|
54
54
|
out_path
|
|
55
55
|
rescue SyntaxError => e
|
data/lib/yarbs/type_converter.rb
CHANGED
|
@@ -21,7 +21,8 @@ module Yarbs
|
|
|
21
21
|
source = yard_types.map { |type| rewrite(type) }.join(" | ")
|
|
22
22
|
|
|
23
23
|
begin
|
|
24
|
-
RBS::Parser.parse_type(source, require_eof: true)
|
|
24
|
+
type = RBS::Parser.parse_type(source, require_eof: true)
|
|
25
|
+
type ? fit_generic_args(type) : UNTYPED
|
|
25
26
|
rescue RBS::ParsingError => e
|
|
26
27
|
message = "yarbs: could not convert YARD type `#{yard_types.join(", ")}` to RBS (#{e.message})"
|
|
27
28
|
raise Error, message if strict
|
|
@@ -31,6 +32,50 @@ module Yarbs
|
|
|
31
32
|
end
|
|
32
33
|
end
|
|
33
34
|
|
|
35
|
+
# Number of type parameters for the core generic classes, which YARD
|
|
36
|
+
# lets you write with any number of arguments (or none) but RBS doesn't.
|
|
37
|
+
GENERIC_ARITY = {
|
|
38
|
+
Array: 1,
|
|
39
|
+
Set: 1,
|
|
40
|
+
Range: 1,
|
|
41
|
+
Enumerable: 1,
|
|
42
|
+
Enumerator: 2,
|
|
43
|
+
Hash: 2
|
|
44
|
+
}.freeze
|
|
45
|
+
private_constant :GENERIC_ARITY
|
|
46
|
+
|
|
47
|
+
# Fits the arguments of core generics to what RBS expects, recursively:
|
|
48
|
+
#
|
|
49
|
+
# - bare `Array`/`Hash` -> `Array[untyped]`/`Hash[untyped, untyped]`
|
|
50
|
+
# - `Array<String, Regexp>` (YARD for "Strings or Regexps") ->
|
|
51
|
+
# `Array[String | Regexp]`
|
|
52
|
+
# - missing trailing arguments are filled with `untyped`
|
|
53
|
+
#
|
|
54
|
+
# @param type [RBS::Types::t]
|
|
55
|
+
# @return [RBS::Types::t]
|
|
56
|
+
def self.fit_generic_args(type)
|
|
57
|
+
case type
|
|
58
|
+
when RBS::Types::ClassInstance
|
|
59
|
+
args = type.args.map { |arg| fit_generic_args(arg) }
|
|
60
|
+
arity = type.name.namespace.path.empty? ? GENERIC_ARITY[type.name.name] : nil
|
|
61
|
+
|
|
62
|
+
if arity
|
|
63
|
+
if arity == 1 && args.size > 1
|
|
64
|
+
args = [RBS::Types::Union.new(types: args, location: nil)]
|
|
65
|
+
elsif args.size < arity
|
|
66
|
+
args += Array.new(arity - args.size, UNTYPED)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
RBS::Types::ClassInstance.new(name: type.name, args: args, location: type.location)
|
|
71
|
+
when RBS::Types::Union, RBS::Types::Intersection, RBS::Types::Optional, RBS::Types::Tuple, RBS::Types::Record, RBS::Types::Proc
|
|
72
|
+
type.map_type { |inner| fit_generic_args(inner) }
|
|
73
|
+
else
|
|
74
|
+
type
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
private_class_method :fit_generic_args
|
|
78
|
+
|
|
34
79
|
# `Proc<(ArgType, ...), ReturnType>` -> `^(ArgType, ...) -> ReturnType`,
|
|
35
80
|
# RBS's proc-literal type (a real, typed callable signature).
|
|
36
81
|
#
|
data/lib/yarbs/version.rb
CHANGED
data/lib/yarbs/writer.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbs"
|
|
4
|
+
|
|
5
|
+
module Yarbs
|
|
6
|
+
# An +RBS::Writer+ that also writes a constant's annotations, which the
|
|
7
|
+
# stock writer drops (even though the RBS parser accepts +%a{...}+ on a
|
|
8
|
+
# constant, and Steep reads it). Without this, a +@deprecated+ constant
|
|
9
|
+
# would silently lose the +%a{deprecated}+ that {Annotator} gives it.
|
|
10
|
+
class Writer < RBS::Writer
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def write_decl(decl)
|
|
14
|
+
return super unless decl.is_a?(RBS::AST::Declarations::Constant)
|
|
15
|
+
|
|
16
|
+
write_comment decl.comment
|
|
17
|
+
write_annotation decl.annotations
|
|
18
|
+
puts "#{decl.name}: #{decl.type}"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/yarbs.rb
CHANGED
|
@@ -7,6 +7,7 @@ require_relative "yarbs/version"
|
|
|
7
7
|
require_relative "yarbs/type_converter"
|
|
8
8
|
require_relative "yarbs/prototype_builder"
|
|
9
9
|
require_relative "yarbs/annotator"
|
|
10
|
+
require_relative "yarbs/writer"
|
|
10
11
|
require_relative "yarbs/generator"
|
|
11
12
|
require_relative "yarbs/watcher"
|
|
12
13
|
require_relative "yarbs/cli"
|
data/sig/yarbs/annotator.rbs
CHANGED
|
@@ -68,6 +68,13 @@ module Yarbs
|
|
|
68
68
|
|
|
69
69
|
def return_types_of: (untyped yard_object) -> (::Array[untyped] | untyped)
|
|
70
70
|
|
|
71
|
+
# Appends a `%a{deprecated}` annotation when the YARD object has a
|
|
72
|
+
# `@deprecated` tag, which Steep reports as `Ruby::DeprecatedReference`
|
|
73
|
+
# wherever the declaration is used. The tag's text becomes the message
|
|
74
|
+
# (`%a{deprecated: Use #bar instead}`), flattened onto one line since
|
|
75
|
+
# Steep only reads the message up to the first newline.
|
|
76
|
+
def with_deprecation: (untyped annotations, untyped yard_object) -> untyped
|
|
77
|
+
|
|
71
78
|
def convert: (untyped types) -> untyped
|
|
72
79
|
|
|
73
80
|
def safe_symbol: (untyped name) -> (nil | untyped)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
module Yarbs
|
|
2
|
+
# An +RBS::Writer+ that also writes a constant's annotations, which the
|
|
3
|
+
# stock writer drops (even though the RBS parser accepts +%a{...}+ on a
|
|
4
|
+
# constant, and Steep reads it). Without this, a +@deprecated+ constant
|
|
5
|
+
# would silently lose the +%a{deprecated}+ that {Annotator} gives it.
|
|
6
|
+
class Writer < RBS::Writer
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def write_decl: (untyped decl) -> untyped
|
|
10
|
+
end
|
|
11
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: yarbs
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- tobidelius
|
|
@@ -70,6 +70,7 @@ files:
|
|
|
70
70
|
- lib/yarbs/type_converter.rb
|
|
71
71
|
- lib/yarbs/version.rb
|
|
72
72
|
- lib/yarbs/watcher.rb
|
|
73
|
+
- lib/yarbs/writer.rb
|
|
73
74
|
- sig/yarbs.rbs
|
|
74
75
|
- sig/yarbs/annotator.rbs
|
|
75
76
|
- sig/yarbs/cli.rbs
|
|
@@ -78,6 +79,7 @@ files:
|
|
|
78
79
|
- sig/yarbs/type_converter.rbs
|
|
79
80
|
- sig/yarbs/version.rbs
|
|
80
81
|
- sig/yarbs/watcher.rbs
|
|
82
|
+
- sig/yarbs/writer.rbs
|
|
81
83
|
homepage: https://github.com/tobidelius/yarbs
|
|
82
84
|
licenses:
|
|
83
85
|
- MIT
|
|
@@ -96,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
96
98
|
- !ruby/object:Gem::Version
|
|
97
99
|
version: '0'
|
|
98
100
|
requirements: []
|
|
99
|
-
rubygems_version: 4.0.
|
|
101
|
+
rubygems_version: 4.0.20
|
|
100
102
|
specification_version: 4
|
|
101
103
|
summary: Generate RBS files from YARD documentation.
|
|
102
104
|
test_files: []
|