Class: RuboCop::Cop::GraphQL::ObjectDescription

Inherits:
Base
  • Object
show all
Includes:
GraphQL::DescriptionMethod
Defined in:
lib/rubocop/cop/graphql/object_description.rb

Overview

This cop checks if a type (object, input, interface, scalar, union, mutation, subscription, and resolver) has a description.

Only classes that actually declare a GraphQL type are checked: those whose superclass resolves to a GraphQL base (Object, InputObject, Union, Enum, Scalar, or anything ending in Mutation, Subscription or Resolver), plus modules that include an *Interface base. Plain Ruby classes that happen to live alongside types - error classes, analyzers, validators, loaders, generators - are skipped, so they no longer need to be silenced one by one.

Two kinds of real type declarations are also skipped, because neither surfaces a description in the schema: abstract Base* types that other types inherit from, and (unless IgnoreRootTypes is disabled) the root operation types Query, Mutation and Subscription.

Examples:

# good

class Types::UserType < Types::BaseObject
  description "Represents application user"
  # ...
end

# bad

class Types::UserType < Types::BaseObject
  # ...
end
# good - not a GraphQL type, so no description is expected

class TrackingInfoNotAvailable < StandardError; end
class UserLoader < GraphQL::Batch::Loader; end
# good - abstract base and root operation types carry no description

class Types::BaseObject < GraphQL::Schema::Object; end
class Types::Query < Types::BaseObject; end

AdditionalTypeBases: [] (default)

# good - `ApplicationType` is not a recognized GraphQL base, so this
# class is not checked

class Types::UserType < ApplicationType
end

AdditionalTypeBases: ['ApplicationType']

# bad - `ApplicationType` is now treated as a GraphQL base

class Types::UserType < ApplicationType
end

Constant Summary collapse

MSG =
"Missing type description"
EXACT_BASES =

Base class names that mark a GraphQL type when they match exactly, or with a Base prefix (GraphQL::Schema::Object, Types::BaseObject). Ambiguous words are deliberately not matched as suffixes, so a plain Ruby ValueObject base is not mistaken for a GraphQL one. Interface is absent on purpose: graphql-ruby interfaces are modules, so a class inheriting an *::Interface constant is always some other abstract base.

%w[Object InputObject Union Enum Scalar].freeze
SUFFIX_BASES =

These read unambiguously as GraphQL even inside a longer name, so they are matched as suffixes (RelayClassicMutation, Base::PermissionedMutation).

%w[Mutation Subscription Resolver].freeze
GRAPHQL_NAMESPACES =

A base named exactly Base (Resolvers::Base) is only a GraphQL base when it sits in a namespace that says so.

%w[
  Types Mutations Subscriptions Resolvers Inputs Interfaces Unions Enums Scalars
].freeze
ROOT_TYPE_NAMES =

GraphQL reserves these names for the root operation types.

%w[Query Mutation Subscription].freeze
ABSTRACT_BASE_NAME =

Base, or Base followed by another word - the naming convention for the abstract types that other types inherit from (BaseObject, BaseInterface).

/\ABase(?:[A-Z]|\z)/
SORBET_NAMESPACE =

Sorbet's T namespace is reserved, and T::Enum / T::Struct collide with the base names above.

:T

Constants included from GraphQL::DescriptionMethod

GraphQL::DescriptionMethod::DESCRIPTION_STRING

Instance Method Summary collapse

Methods included from GraphQL::DescriptionMethod

#description_method_call?, #description_with_block_arg?, #find_description_method

Instance Method Details

#on_class(node) ⇒ Object



95
96
97
98
99
100
101
# File 'lib/rubocop/cop/graphql/object_description.rb', line 95

def on_class(node)
  return unless graphql_type_class?(node)
  return if exempt_type?(node)
  return if described_or_root_named?(node)

  add_offense(node.identifier)
end

#on_module(node) ⇒ Object



103
104
105
106
107
108
# File 'lib/rubocop/cop/graphql/object_description.rb', line 103

def on_module(node)
  return if abstract_base?(node)
  return unless undescribed_interface_module?(node)

  add_offense(node.identifier)
end