Skip to content
Snippets Groups Projects

Add a rule to enforce resolver type annotations

Merged Alex Kalderimis requested to merge ajk-rubocop-resolver-type into master
All threads resolved!
4 files
+ 168
0
Compare changes
  • Side-by-side
  • Inline
Files
4
  • f44aa6eb
    This new rubocop rule enforces that all resolvers declare their type.
    
    This is important for several reasons:
    
    - developers can read a resolver and know what it does, by understanding
      what it is meant to return.
    - we can enable better testing of resolvers, by creating fields from
      resolvers using `Resolver.field_options`.
    - Resolvers become the SSOT for field metadata, enabling us to eliminate
      repetition and boilerplate.
+ 59
0
 
# frozen_string_literal: true
 
 
# This cop checks for missing GraphQL type annotations on resolvers
 
#
 
# @example
 
#
 
# # bad
 
# module Resolvers
 
# class NoType < BaseResolver
 
# field :some_field, GraphQL::STRING_TYPE
 
# end
 
# end
 
#
 
# # good
 
# module Resolvers
 
# class WithType < BaseResolver
 
# type MyType, null: true
 
#
 
# field :some_field, GraphQL::STRING_TYPE
 
# end
 
# end
 
 
module RuboCop
 
module Cop
 
module Graphql
 
class ResolverType < RuboCop::Cop::Cop
 
MSG = 'Missing type annotation: Please add `type` DSL method call. ' \
 
'e.g: type UserType.connection_type, null: true'
 
 
def_node_matcher :type_dsl_call?, <<~PATTERN
 
(send nil? :type ...)
 
PATTERN
 
 
def on_class(node)
 
add_offense(node, location: :expression) if resolver?(node) && !typed?(node)
 
end
 
 
private
 
 
def typed?(class_node)
 
body = class_node.children[2]&.children
 
return false unless body
 
 
body.any? { |declaration| type_dsl_call?(declaration) }
 
end
 
 
def resolver?(node)
 
class_name = class_constant(node)&.short_name&.to_s
 
 
!class_name.nil? && class_name.end_with?('Resolver')
 
end
 
 
def class_constant(node)
 
node.descendants.first
 
end
 
end
 
end
 
end
 
end
Loading