class

Analyzer::Ruby::Graphql

Inherits Analyzer::Ruby::RubyEngine < Analyzer < FileHelper < Reference < Object

graphql-ruby (code-first GraphQL). The schema lives in Ruby classes, not SDL: class AppSchema < GraphQL::Schema binds query Types::QueryType (and mutation/subscription), and each root type declares field :post, PostType do argument :id, ID end, or delegates to a resolver: / mutation: class that declares its own arguments. Each root field becomes one endpoint in the shape the SDL analyzers emit.

Two passes: every .rb file is line-scanned into class/module bodies (fields, arguments, includes, superclass), then roots, resolvers and mixins are resolved across files by constant name. Class bodies are closed by indentation, which holds for conventionally formatted Ruby.

Constants

ARGUMENT_RE = /^\s*argument[\s(]/
CALL_HEAD_RE = /\A\s*(?:field|argument)\s*(\()?/
CLASS_RE = /^\s*(?:class|module)\s+((?:::)?[A-Z][\w:]*)(?:\s*<\s*((?:::)?[A-Z][\w:]*))?/
CONNECTION_ARGS = [{name: "after", type: "String"}, {name: "before", type: "String"}, {name: "first", type: "Int"}, {name: "last", type: "Int"}]

A field whose return type is a *Connection gets these four arguments.

DO_TAIL_RE = /\s+do(?:\s*\|[^|]*\|)?\s*\z/
END_RE = /^\s*end\b/
FALLBACK_ROOTS = {"QueryType" => "Query", "Query" => "Query", "MutationType" => "Mutation", "Mutation" => "Mutation", "SubscriptionType" => "Subscription", "Subscription" => "Subscription"}
FIELD_RE = /^\s*field[\s(]/
FILE_GATE_RE = /GraphQL::|graphql#|^\s*(?:field|argument)\b/m

A file carries something this analyzer reads only if it names graphql-ruby, declares a field/argument, or routes to a GraphQL controller.

GRAPHQL_NAME_RE = /^\s*graphql_name\s*\(?\s*["']([^"']+)["']/
INCLUDE_RE = /^\s*(?:include|implements|add_field)\s*\(?\s*((?:::)?[A-Z][\w:]*)/
KWARG_RE = /\A(\w+):(?!:)\s*(.*)\z/m
MOUNT_RE = /["']([^"'\s]+)["']\s*(?:,\s*to:\s*|=>\s*)["'][\w\/]*graphql#\w+["']/

Rails: post "/graphql", to: "graphql#execute" (or the => form).

NULL_TRUE_RE = /\Anull:\s*true\z/
ONE_LINE_END_RE = /;\s*end\s*$/
RELAY_NODE_FIELDS = {"HasNodeField" => {"node", [{name: "id", type: "ID!"}], "Node"}, "HasNodesField" => {"nodes", [{name: "ids", type: "[ID!]!"}], "[Node]!"}, "NodeField" => {"node", [{name: "id", type: "ID!"}], "Node"}, "NodesField" => {"nodes", [{name: "ids", type: "[ID!]!"}], "[Node]!"}}

include GraphQL::Types::Relay::HasNodeField / HasNodesField (or the legacy add_field GraphQL::Types::Relay::NodeField) add these fields.

ROOT_KINDS = {"query" => "Query", "mutation" => "Mutation", "subscription" => "Subscription"}
ROOT_RE = /^\s*(query|mutation|subscription)\s*\(?\s*((?:::)?[A-Z][\w:]*)/
SCALAR_ALIASES = {"Integer" => "Int"}

Ruby class names graphql-ruby maps to built-in scalars.

SYMBOL_NAME_RE = /\A:(\w+[?!]?)\z|\A["'](\w+)["']\z/
TAG_SOURCE = "ruby_graphql_analyzer"
TYPE_DECL_RE = /^\s*type\s*\(?\s*([\["'A-Z:].*)$/

Class methods

tech_name
Source

Instance methods

analyze
Source
tech

Instance-side view of the same declaration. The per-file rescues live on this base class, which has no way to name the analyzer that is running inside them, so a skipped file could not be attributed to a tech. Deriving it from analyzer_for keeps the name written exactly once.

Source

Nested types