Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix top_const_ref parsing #63

Merged
merged 1 commit into from
Jun 14, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
---
inherit_from: .rubocop_todo.yml

require:
- rubocop-performance
- rubocop-rake
Expand Down
22 changes: 0 additions & 22 deletions .rubocop_todo.yml

This file was deleted.

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Bug fixes

* [#61](https://github.com/dduugg/yard-sorbet/pull/61) Fix parsing of `sig` with nested return types
* [#62](https://github.com/dduugg/yard-sorbet/pull/61) Fix parsing of `top_const_ref` nodes (e.g. `::Foo`)

### Changes

Expand Down
83 changes: 44 additions & 39 deletions lib/yard-sorbet/sig_to_yard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,30 +8,33 @@ module YARDSorbet::SigToYARD
# @see https://yardoc.org/types.html
sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
def self.convert(node)
types = convert_type(node)
types = convert_node(node)
# scrub newlines, as they break the YARD parser
types.map { |type| type.gsub(/\n\s*/, ' ') }
end

sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
private_class_method def self.convert_type(node)
return handle_call(node) if node.is_a? YARD::Parser::Ruby::MethodCallNode
private_class_method def self.convert_node(node)
case node
when YARD::Parser::Ruby::MethodCallNode then handle_call(node)
when YARD::Parser::Ruby::ReferenceNode then handle_ref(node)
else convert_node_type(node)
end
end

sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
private_class_method def self.convert_node_type(node)
case node.type
when :aref then handle_aref(node)
when :arg_paren then handle_arg_paren(node)
when :array then handle_array(node)
when :const_path_ref, :const then handle_const(node)
when :const then handle_ref(node)
# Fixed hashes as return values are unsupported:
# https://github.com/lsegal/yard/issues/425
#
# Hash key params can be individually documented with `@option`, but
# sig translation is unsupported.
# sig translation is currently unsupported.
when :hash, :list then ['Hash']
when :var_ref then handle_var_ref(node)
# A top-level constant reference, such as ::Klass
# It contains a child node of type :const
when :top_const_ref then convert(node.first)
else
log.warn("Unsupported sig #{node.type} node #{node.source}")
[node.source]
Expand All @@ -52,21 +55,34 @@ def self.convert(node)
private_class_method def self.handle_aref(node)
# https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Parametrized_Types
case node.first.source
when 'T::Array', 'T::Enumerable', 'T::Range', 'T::Set'
collection_type = node.first.source.split('::').last
member_type = convert(node.last.first).join(', ')
["#{collection_type}<#{member_type}>"]
when 'T::Hash'
kv = node.last.children
key_type = convert(kv.first).join(', ')
value_type = convert(kv.last).join(', ')
["Hash{#{key_type} => #{value_type}}"]
when 'T::Array', 'T::Enumerable', 'T::Range', 'T::Set' then handle_collection(node)
when 'T::Hash' then handle_hash(node)
else
log.info("Unsupported sig aref node #{node.source}")
[build_generic_type(node)]
end
end

sig { params(node: YARD::Parser::Ruby::MethodCallNode).returns(T::Array[String]) }
private_class_method def self.handle_call(node)
node.namespace.source == 'T' ? handle_t_method(node.method_name(true), node) : [node.source]
end

sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
private_class_method def self.handle_collection(node)
collection_type = node.first.source.split('::').last
member_type = convert(node.last.first).join(', ')
["#{collection_type}<#{member_type}>"]
end

sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
private_class_method def self.handle_hash(node)
kv = node.last.children
key_type = convert(kv.first).join(', ')
value_type = convert(kv.last).join(', ')
["Hash{#{key_type} => #{value_type}}"]
end

sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
private_class_method def self.handle_arg_paren(node)
convert(node.first.first)
Expand All @@ -80,24 +96,19 @@ def self.convert(node)
end

sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
private_class_method def self.handle_const(node)
private_class_method def self.handle_ref(node)
source = node.source
case source
# YARD convention for booleans
when 'T::Boolean' then ['Boolean']
when 'T::Boolean' then ['Boolean'] # YARD convention for booleans
# YARD convention is use singleton objects when applicable:
# https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Literals
when 'FalseClass' then ['false']
when 'NilClass' then ['nil']
when 'TrueClass' then ['true']
else [source]
end
end

sig { params(node: YARD::Parser::Ruby::MethodCallNode).returns(T::Array[String]) }
private_class_method def self.handle_call(node)
if node.namespace.source == 'T'
handle_t_method(node.method_name(true), node)
else
[node.source]
end
end

sig { params(method_name: Symbol, node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
private_class_method def self.handle_t_method(method_name, node)
case method_name
Expand All @@ -115,14 +126,8 @@ def self.convert(node)
end

sig { params(node: YARD::Parser::Ruby::AstNode).returns(T::Array[String]) }
private_class_method def self.handle_var_ref(node)
# YARD convention is use singleton objects when applicable:
# https://www.rubydoc.info/gems/yard/file/docs/Tags.md#Literals
case node.source
when 'FalseClass' then ['false']
when 'NilClass' then ['nil']
when 'TrueClass' then ['true']
else [node.source]
end
private_class_method def self.handle_unknown(node)
log.warn("Unsupported sig #{node.type} node #{node.source}")
[node.source]
end
end
2 changes: 1 addition & 1 deletion spec/yard_sorbet/handlers/sig_handler_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@

it 'top_const_ref' do
node = YARD::Registry.at('VariousTypedSigs#top_const_ref')
expect(node.tag(:return).types).to eq(['Foo'])
expect(node.tag(:return).types).to eq(['::Foo'])
end

it 'handles inline visibility modifiers' do
Expand Down