async-graphql/src/validation/visitor.rs

678 lines
21 KiB
Rust
Raw Normal View History

2020-03-22 08:45:59 +00:00
use crate::error::RuleError;
use crate::registry;
2020-04-05 08:00:26 +00:00
use crate::registry::{Type, TypeName};
2020-03-08 12:35:36 +00:00
use graphql_parser::query::{
Definition, Directive, Document, Field, FragmentDefinition, FragmentSpread, InlineFragment,
2020-04-05 08:00:26 +00:00
OperationDefinition, Selection, SelectionSet, TypeCondition, Value, VariableDefinition,
2020-03-08 12:35:36 +00:00
};
2020-03-09 12:39:46 +00:00
use graphql_parser::Pos;
2020-03-22 08:45:59 +00:00
use std::collections::HashMap;
pub struct VisitorContext<'a> {
pub registry: &'a registry::Registry,
pub errors: Vec<RuleError>,
2020-04-05 08:00:26 +00:00
type_stack: Vec<Option<&'a registry::Type>>,
input_type: Vec<Option<TypeName<'a>>>,
2020-03-22 08:45:59 +00:00
fragments: HashMap<&'a str, &'a FragmentDefinition>,
}
impl<'a> VisitorContext<'a> {
pub fn new(registry: &'a registry::Registry, doc: &'a Document) -> Self {
Self {
registry,
errors: Default::default(),
type_stack: Default::default(),
2020-04-05 08:00:26 +00:00
input_type: Default::default(),
2020-03-22 08:45:59 +00:00
fragments: doc
.definitions
.iter()
.filter_map(|d| match d {
Definition::Fragment(fragment) => Some((fragment.name.as_str(), fragment)),
_ => None,
})
.collect(),
}
}
pub fn report_error<T: Into<String>>(&mut self, locations: Vec<Pos>, msg: T) {
self.errors.push(RuleError {
locations,
message: msg.into(),
})
}
pub fn append_errors(&mut self, errors: Vec<RuleError>) {
self.errors.extend(errors);
}
pub fn with_type<F: FnMut(&mut VisitorContext<'a>)>(
&mut self,
2020-04-05 08:00:26 +00:00
ty: Option<&'a registry::Type>,
2020-03-22 08:45:59 +00:00
mut f: F,
) {
self.type_stack.push(ty);
f(self);
self.type_stack.pop();
}
2020-04-05 08:00:26 +00:00
pub fn with_input_type<F: FnMut(&mut VisitorContext<'a>)>(
&mut self,
ty: Option<TypeName<'a>>,
mut f: F,
) {
self.input_type.push(ty);
f(self);
self.input_type.pop();
}
2020-03-22 08:45:59 +00:00
pub fn parent_type(&self) -> Option<&'a registry::Type> {
if self.type_stack.len() >= 2 {
2020-04-05 08:00:26 +00:00
self.type_stack
.get(self.type_stack.len() - 2)
.copied()
.flatten()
2020-03-22 08:45:59 +00:00
} else {
None
}
}
2020-04-05 08:00:26 +00:00
pub fn current_type(&self) -> Option<&'a registry::Type> {
self.type_stack.last().copied().flatten()
2020-03-22 08:45:59 +00:00
}
pub fn is_known_fragment(&self, name: &str) -> bool {
self.fragments.contains_key(name)
}
pub fn fragment(&self, name: &str) -> Option<&'a FragmentDefinition> {
self.fragments.get(name).copied()
}
}
2020-03-08 12:35:36 +00:00
pub trait Visitor<'a> {
2020-03-22 08:45:59 +00:00
fn enter_document(&mut self, _ctx: &mut VisitorContext<'a>, _doc: &'a Document) {}
fn exit_document(&mut self, _ctx: &mut VisitorContext<'a>, _doc: &'a Document) {}
2020-03-08 12:35:36 +00:00
fn enter_operation_definition(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
_operation_definition: &'a OperationDefinition,
) {
}
fn exit_operation_definition(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
_operation_definition: &'a OperationDefinition,
) {
}
fn enter_fragment_definition(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
_fragment_definition: &'a FragmentDefinition,
) {
}
fn exit_fragment_definition(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
_fragment_definition: &'a FragmentDefinition,
) {
}
fn enter_variable_definition(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
_variable_definition: &'a VariableDefinition,
) {
}
fn exit_variable_definition(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
_variable_definition: &'a VariableDefinition,
) {
}
2020-03-22 08:45:59 +00:00
fn enter_directive(&mut self, _ctx: &mut VisitorContext<'a>, _directive: &'a Directive) {}
fn exit_directive(&mut self, _ctx: &mut VisitorContext<'a>, _directive: &'a Directive) {}
2020-03-08 12:35:36 +00:00
2020-03-09 12:39:46 +00:00
fn enter_argument(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-09 12:39:46 +00:00
_pos: Pos,
_name: &'a str,
_value: &'a Value,
) {
}
fn exit_argument(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-09 12:39:46 +00:00
_pos: Pos,
_name: &'a str,
_value: &'a Value,
) {
}
2020-03-08 12:35:36 +00:00
2020-03-12 09:11:02 +00:00
fn enter_selection_set(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-12 09:11:02 +00:00
_selection_set: &'a SelectionSet,
) {
}
fn exit_selection_set(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-12 09:11:02 +00:00
_selection_set: &'a SelectionSet,
) {
}
2020-03-22 08:45:59 +00:00
fn enter_selection(&mut self, _ctx: &mut VisitorContext<'a>, _selection: &'a Selection) {}
fn exit_selection(&mut self, _ctx: &mut VisitorContext<'a>, _selection: &'a Selection) {}
2020-03-08 12:35:36 +00:00
2020-03-22 08:45:59 +00:00
fn enter_field(&mut self, _ctx: &mut VisitorContext<'a>, _field: &'a Field) {}
fn exit_field(&mut self, _ctx: &mut VisitorContext<'a>, _field: &'a Field) {}
2020-03-08 12:35:36 +00:00
fn enter_fragment_spread(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
_fragment_spread: &'a FragmentSpread,
) {
}
fn exit_fragment_spread(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
_fragment_spread: &'a FragmentSpread,
) {
}
fn enter_inline_fragment(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
_inline_fragment: &'a InlineFragment,
) {
}
fn exit_inline_fragment(
&mut self,
2020-03-22 08:45:59 +00:00
_ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
_inline_fragment: &'a InlineFragment,
) {
}
2020-04-05 08:00:26 +00:00
fn enter_input_value(
&mut self,
_ctx: &mut VisitorContext<'a>,
_pos: Pos,
_expected_type: &Option<TypeName<'a>>,
_value: &'a Value,
) {
}
fn exit_input_value(
&mut self,
_ctx: &mut VisitorContext<'a>,
_pos: Pos,
_expected_type: &Option<TypeName<'a>>,
_value: &Value,
) {
}
2020-03-08 12:35:36 +00:00
}
pub struct VisitorNil;
impl VisitorNil {
pub fn with<V>(self, visitor: V) -> VisitorCons<V, Self> {
VisitorCons(visitor, self)
}
}
pub struct VisitorCons<A, B>(A, B);
impl<A, B> VisitorCons<A, B> {
pub fn with<V>(self, visitor: V) -> VisitorCons<V, Self> {
VisitorCons(visitor, self)
}
}
impl<'a> Visitor<'a> for VisitorNil {}
impl<'a, A, B> Visitor<'a> for VisitorCons<A, B>
where
A: Visitor<'a> + 'a,
B: Visitor<'a> + 'a,
{
2020-03-22 08:45:59 +00:00
fn enter_document(&mut self, ctx: &mut VisitorContext<'a>, doc: &'a Document) {
2020-03-08 12:35:36 +00:00
self.0.enter_document(ctx, doc);
self.1.enter_document(ctx, doc);
}
2020-03-22 08:45:59 +00:00
fn exit_document(&mut self, ctx: &mut VisitorContext<'a>, doc: &'a Document) {
2020-03-08 12:35:36 +00:00
self.0.exit_document(ctx, doc);
self.1.exit_document(ctx, doc);
}
fn enter_operation_definition(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
operation_definition: &'a OperationDefinition,
) {
self.0.enter_operation_definition(ctx, operation_definition);
self.1.enter_operation_definition(ctx, operation_definition);
}
fn exit_operation_definition(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
operation_definition: &'a OperationDefinition,
) {
self.0.exit_operation_definition(ctx, operation_definition);
self.1.exit_operation_definition(ctx, operation_definition);
}
fn enter_fragment_definition(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
fragment_definition: &'a FragmentDefinition,
) {
self.0.enter_fragment_definition(ctx, fragment_definition);
self.1.enter_fragment_definition(ctx, fragment_definition);
}
fn exit_fragment_definition(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
fragment_definition: &'a FragmentDefinition,
) {
self.0.exit_fragment_definition(ctx, fragment_definition);
self.1.exit_fragment_definition(ctx, fragment_definition);
}
fn enter_variable_definition(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
variable_definition: &'a VariableDefinition,
) {
self.0.enter_variable_definition(ctx, variable_definition);
self.1.enter_variable_definition(ctx, variable_definition);
}
fn exit_variable_definition(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
variable_definition: &'a VariableDefinition,
) {
self.0.exit_variable_definition(ctx, variable_definition);
self.1.exit_variable_definition(ctx, variable_definition);
}
2020-03-22 08:45:59 +00:00
fn enter_directive(&mut self, ctx: &mut VisitorContext<'a>, directive: &'a Directive) {
2020-03-08 12:35:36 +00:00
self.0.enter_directive(ctx, directive);
self.1.enter_directive(ctx, directive);
}
2020-03-22 08:45:59 +00:00
fn exit_directive(&mut self, ctx: &mut VisitorContext<'a>, directive: &'a Directive) {
2020-03-08 12:35:36 +00:00
self.0.exit_directive(ctx, directive);
self.1.exit_directive(ctx, directive);
}
2020-03-09 12:39:46 +00:00
fn enter_argument(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-09 12:39:46 +00:00
pos: Pos,
name: &'a str,
value: &'a Value,
) {
self.0.enter_argument(ctx, pos, name, value);
self.1.enter_argument(ctx, pos, name, value);
2020-03-08 12:35:36 +00:00
}
2020-03-09 12:39:46 +00:00
fn exit_argument(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-09 12:39:46 +00:00
pos: Pos,
name: &'a str,
value: &'a Value,
) {
self.0.exit_argument(ctx, pos, name, value);
self.1.exit_argument(ctx, pos, name, value);
2020-03-08 12:35:36 +00:00
}
2020-03-12 09:11:02 +00:00
fn enter_selection_set(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-12 09:11:02 +00:00
selection_set: &'a SelectionSet,
) {
self.0.enter_selection_set(ctx, selection_set);
self.1.enter_selection_set(ctx, selection_set);
}
fn exit_selection_set(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-12 09:11:02 +00:00
selection_set: &'a SelectionSet,
) {
self.0.exit_selection_set(ctx, selection_set);
self.1.exit_selection_set(ctx, selection_set);
}
2020-03-22 08:45:59 +00:00
fn enter_selection(&mut self, ctx: &mut VisitorContext<'a>, selection: &'a Selection) {
2020-03-08 12:35:36 +00:00
self.0.enter_selection(ctx, selection);
self.1.enter_selection(ctx, selection);
}
2020-03-22 08:45:59 +00:00
fn exit_selection(&mut self, ctx: &mut VisitorContext<'a>, selection: &'a Selection) {
2020-03-08 12:35:36 +00:00
self.0.exit_selection(ctx, selection);
self.1.exit_selection(ctx, selection);
}
2020-03-22 08:45:59 +00:00
fn enter_field(&mut self, ctx: &mut VisitorContext<'a>, field: &'a Field) {
2020-03-08 12:35:36 +00:00
self.0.enter_field(ctx, field);
self.1.enter_field(ctx, field);
}
2020-03-22 08:45:59 +00:00
fn exit_field(&mut self, ctx: &mut VisitorContext<'a>, field: &'a Field) {
2020-03-08 12:35:36 +00:00
self.0.exit_field(ctx, field);
self.1.exit_field(ctx, field);
}
fn enter_fragment_spread(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
fragment_spread: &'a FragmentSpread,
) {
self.0.enter_fragment_spread(ctx, fragment_spread);
self.1.enter_fragment_spread(ctx, fragment_spread);
}
fn exit_fragment_spread(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
fragment_spread: &'a FragmentSpread,
) {
self.0.exit_fragment_spread(ctx, fragment_spread);
self.1.exit_fragment_spread(ctx, fragment_spread);
}
fn enter_inline_fragment(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
inline_fragment: &'a InlineFragment,
) {
self.0.enter_inline_fragment(ctx, inline_fragment);
self.1.enter_inline_fragment(ctx, inline_fragment);
}
fn exit_inline_fragment(
&mut self,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
inline_fragment: &'a InlineFragment,
) {
self.0.exit_inline_fragment(ctx, inline_fragment);
self.1.exit_inline_fragment(ctx, inline_fragment);
}
}
2020-03-22 08:45:59 +00:00
pub fn visit<'a, V: Visitor<'a>>(v: &mut V, ctx: &mut VisitorContext<'a>, doc: &'a Document) {
2020-03-08 12:35:36 +00:00
v.enter_document(ctx, doc);
visit_definitions(v, ctx, doc);
v.exit_document(ctx, doc);
}
fn visit_definitions<'a, V: Visitor<'a>>(
v: &mut V,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
doc: &'a Document,
) {
for d in &doc.definitions {
match d {
Definition::Operation(operation) => {
visit_operation_definition(v, ctx, operation);
}
Definition::Fragment(fragment) => {
let TypeCondition::On(name) = &fragment.type_condition;
2020-04-05 08:00:26 +00:00
ctx.with_type(ctx.registry.types.get(name), |ctx| {
visit_fragment_definition(v, ctx, fragment)
});
2020-03-08 12:35:36 +00:00
}
}
}
}
fn visit_operation_definition<'a, V: Visitor<'a>>(
v: &mut V,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
operation: &'a OperationDefinition,
) {
v.enter_operation_definition(ctx, operation);
match operation {
OperationDefinition::SelectionSet(selection_set) => {
2020-04-05 08:00:26 +00:00
ctx.with_type(Some(&ctx.registry.types[&ctx.registry.query_type]), |ctx| {
2020-03-08 12:35:36 +00:00
visit_selection_set(v, ctx, selection_set)
});
}
OperationDefinition::Query(query) => {
2020-04-05 08:00:26 +00:00
ctx.with_type(Some(&ctx.registry.types[&ctx.registry.query_type]), |ctx| {
2020-03-08 12:35:36 +00:00
visit_variable_definitions(v, ctx, &query.variable_definitions);
visit_directives(v, ctx, &query.directives);
visit_selection_set(v, ctx, &query.selection_set);
});
}
OperationDefinition::Mutation(mutation) => {
if let Some(mutation_type) = &ctx.registry.mutation_type {
2020-04-05 08:00:26 +00:00
ctx.with_type(Some(&ctx.registry.types[mutation_type]), |ctx| {
2020-03-08 12:35:36 +00:00
visit_variable_definitions(v, ctx, &mutation.variable_definitions);
visit_directives(v, ctx, &mutation.directives);
visit_selection_set(v, ctx, &mutation.selection_set);
});
} else {
ctx.report_error(
vec![mutation.position],
"Schema is not configured for mutations.",
);
}
}
OperationDefinition::Subscription(subscription) => {
2020-03-17 09:26:59 +00:00
if let Some(subscription_type) = &ctx.registry.subscription_type {
2020-04-05 08:00:26 +00:00
ctx.with_type(Some(&ctx.registry.types[subscription_type]), |ctx| {
2020-03-17 09:26:59 +00:00
visit_variable_definitions(v, ctx, &subscription.variable_definitions);
visit_directives(v, ctx, &subscription.directives);
visit_selection_set(v, ctx, &subscription.selection_set);
});
} else {
ctx.report_error(
vec![subscription.position],
"Schema is not configured for subscriptions.",
);
}
2020-03-08 12:35:36 +00:00
}
}
v.exit_operation_definition(ctx, operation);
}
fn visit_selection_set<'a, V: Visitor<'a>>(
v: &mut V,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
selection_set: &'a SelectionSet,
) {
2020-03-25 07:07:16 +00:00
if !selection_set.items.is_empty() {
v.enter_selection_set(ctx, selection_set);
for selection in &selection_set.items {
visit_selection(v, ctx, selection);
}
v.exit_selection_set(ctx, selection_set);
2020-03-08 12:35:36 +00:00
}
}
fn visit_selection<'a, V: Visitor<'a>>(
v: &mut V,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
selection: &'a Selection,
) {
v.enter_selection(ctx, selection);
match selection {
2020-03-09 04:08:50 +00:00
Selection::Field(field) => {
if field.name != "__typename" {
2020-04-05 08:00:26 +00:00
ctx.with_type(
ctx.current_type()
.and_then(|ty| ty.field_by_name(&field.name))
.and_then(|schema_field| {
ctx.registry.basic_type_by_typename(&schema_field.ty)
}),
|ctx| {
visit_field(v, ctx, field);
},
);
2020-03-09 04:08:50 +00:00
}
}
2020-03-08 12:35:36 +00:00
Selection::FragmentSpread(fragment_spread) => {
visit_fragment_spread(v, ctx, fragment_spread)
}
Selection::InlineFragment(inline_fragment) => {
2020-03-09 04:08:50 +00:00
if let Some(TypeCondition::On(name)) = &inline_fragment.type_condition {
2020-04-05 08:00:26 +00:00
ctx.with_type(ctx.registry.types.get(name), |ctx| {
visit_inline_fragment(v, ctx, inline_fragment)
});
2020-03-09 04:08:50 +00:00
}
2020-03-08 12:35:36 +00:00
}
}
v.exit_selection(ctx, selection);
}
2020-03-22 08:45:59 +00:00
fn visit_field<'a, V: Visitor<'a>>(v: &mut V, ctx: &mut VisitorContext<'a>, field: &'a Field) {
2020-03-08 12:35:36 +00:00
v.enter_field(ctx, field);
2020-04-05 08:00:26 +00:00
for (name, value) in &field.arguments {
v.enter_argument(ctx, field.position, name, value);
let expected_ty = ctx
.parent_type()
.and_then(|ty| ty.field_by_name(&field.name))
.and_then(|schema_field| schema_field.args.get(name.as_str()))
.map(|input_ty| TypeName::create(&input_ty.ty));
ctx.with_input_type(expected_ty, |ctx| {
visit_input_value(v, ctx, field.position, expected_ty, value)
});
v.exit_argument(ctx, field.position, name, value);
}
2020-03-08 12:35:36 +00:00
visit_directives(v, ctx, &field.directives);
2020-03-09 04:08:50 +00:00
visit_selection_set(v, ctx, &field.selection_set);
2020-03-08 12:35:36 +00:00
v.exit_field(ctx, field);
}
2020-04-05 08:00:26 +00:00
fn visit_input_value<'a, V: Visitor<'a>>(
2020-03-08 12:35:36 +00:00
v: &mut V,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-09 12:39:46 +00:00
pos: Pos,
2020-04-05 08:00:26 +00:00
expected_ty: Option<TypeName<'a>>,
value: &'a Value,
2020-03-08 12:35:36 +00:00
) {
2020-04-05 08:00:26 +00:00
v.enter_input_value(ctx, pos, &expected_ty, value);
match value {
Value::List(values) => {
if let Some(expected_ty) = expected_ty {
let elem_ty = expected_ty.unwrap_non_null();
if let TypeName::List(expected_ty) = elem_ty {
values.iter().for_each(|value| {
visit_input_value(v, ctx, pos, Some(TypeName::create(expected_ty)), value)
});
}
}
}
Value::Object(values) => {
if let Some(expected_ty) = expected_ty {
let expected_ty = expected_ty.unwrap_non_null();
if let TypeName::Named(expected_ty) = expected_ty {
if let Some(ty) = ctx
.registry
.types
.get(TypeName::get_basic_typename(expected_ty))
{
if let Type::InputObject { input_fields, .. } = ty {
for (item_key, item_value) in values {
if let Some(input_value) = input_fields.get(item_key) {
visit_input_value(
v,
ctx,
pos,
Some(TypeName::create(&input_value.ty)),
item_value,
);
}
}
}
}
}
}
}
_ => {}
2020-03-08 12:35:36 +00:00
}
2020-04-05 08:00:26 +00:00
v.exit_input_value(ctx, pos, &expected_ty, value);
2020-03-08 12:35:36 +00:00
}
fn visit_variable_definitions<'a, V: Visitor<'a>>(
v: &mut V,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-21 01:32:13 +00:00
variable_definitions: &'a [VariableDefinition],
2020-03-08 12:35:36 +00:00
) {
for d in variable_definitions {
v.enter_variable_definition(ctx, d);
v.exit_variable_definition(ctx, d);
}
}
fn visit_directives<'a, V: Visitor<'a>>(
v: &mut V,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-21 01:32:13 +00:00
directives: &'a [Directive],
2020-03-08 12:35:36 +00:00
) {
for d in directives {
v.enter_directive(ctx, d);
2020-04-05 08:00:26 +00:00
let schema_directive = ctx.registry.directives.get(&d.name);
for (name, value) in &d.arguments {
v.enter_argument(ctx, d.position, name, value);
let expected_ty = schema_directive
.and_then(|schema_directive| schema_directive.args.get(name.as_str()))
.and_then(|input_ty| Some(TypeName::create(&input_ty.ty)));
ctx.with_input_type(expected_ty, |ctx| {
visit_input_value(v, ctx, d.position, expected_ty, value)
});
v.exit_argument(ctx, d.position, name, value);
}
2020-03-08 12:35:36 +00:00
v.exit_directive(ctx, d);
}
}
fn visit_fragment_definition<'a, V: Visitor<'a>>(
v: &mut V,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
fragment: &'a FragmentDefinition,
) {
v.enter_fragment_definition(ctx, fragment);
visit_directives(v, ctx, &fragment.directives);
visit_selection_set(v, ctx, &fragment.selection_set);
v.exit_fragment_definition(ctx, fragment);
}
fn visit_fragment_spread<'a, V: Visitor<'a>>(
v: &mut V,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
fragment_spread: &'a FragmentSpread,
) {
v.enter_fragment_spread(ctx, fragment_spread);
visit_directives(v, ctx, &fragment_spread.directives);
v.exit_fragment_spread(ctx, fragment_spread);
}
fn visit_inline_fragment<'a, V: Visitor<'a>>(
v: &mut V,
2020-03-22 08:45:59 +00:00
ctx: &mut VisitorContext<'a>,
2020-03-08 12:35:36 +00:00
inline_fragment: &'a InlineFragment,
) {
v.enter_inline_fragment(ctx, inline_fragment);
visit_directives(v, ctx, &inline_fragment.directives);
visit_selection_set(v, ctx, &inline_fragment.selection_set);
v.exit_inline_fragment(ctx, inline_fragment);
}