1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
use crate::model::__DirectiveLocation; use crate::validation::context::ValidatorContext; use crate::validation::visitor::Visitor; use graphql_parser::query::{ Field, FragmentDefinition, FragmentSpread, InlineFragment, OperationDefinition, }; use graphql_parser::schema::Directive; #[derive(Default)] pub struct KnownDirectives { location_stack: Vec<__DirectiveLocation>, } impl<'a> Visitor<'a> for KnownDirectives { fn enter_operation_definition( &mut self, _ctx: &mut ValidatorContext<'a>, operation_definition: &'a OperationDefinition, ) { self.location_stack.push(match operation_definition { OperationDefinition::SelectionSet(_) | OperationDefinition::Query(_) => { __DirectiveLocation::QUERY } OperationDefinition::Mutation(_) => __DirectiveLocation::MUTATION, OperationDefinition::Subscription(_) => __DirectiveLocation::SUBSCRIPTION, }); } fn exit_operation_definition( &mut self, _ctx: &mut ValidatorContext<'a>, _operation_definition: &'a OperationDefinition, ) { self.location_stack.pop(); } fn enter_fragment_definition( &mut self, _ctx: &mut ValidatorContext<'a>, _fragment_definition: &'a FragmentDefinition, ) { self.location_stack .push(__DirectiveLocation::FRAGMENT_DEFINITION); } fn exit_fragment_definition( &mut self, _ctx: &mut ValidatorContext<'a>, _fragment_definition: &'a FragmentDefinition, ) { self.location_stack.pop(); } fn enter_directive(&mut self, ctx: &mut ValidatorContext<'a>, directive: &'a Directive) { if let Some(schema_directive) = ctx.registry.directives.get(directive.name.as_str()) { if let Some(current_location) = self.location_stack.last() { if !schema_directive.locations.contains(current_location) { ctx.report_error( vec![directive.position], format!( "Directive \"{}\" may not be used on \"{:?}\"", directive.name, current_location ), ) } } } else { ctx.report_error( vec![directive.position], format!("Unknown directive \"{}\"", directive.name), ); } } fn enter_field(&mut self, _ctx: &mut ValidatorContext<'a>, _field: &'a Field) { self.location_stack.push(__DirectiveLocation::FIELD); } fn exit_field(&mut self, _ctx: &mut ValidatorContext<'a>, _field: &'a Field) { self.location_stack.pop(); } fn enter_fragment_spread( &mut self, _ctx: &mut ValidatorContext<'a>, _fragment_spread: &'a FragmentSpread, ) { self.location_stack .push(__DirectiveLocation::FRAGMENT_SPREAD); } fn exit_fragment_spread( &mut self, _ctx: &mut ValidatorContext<'a>, _fragment_spread: &'a FragmentSpread, ) { self.location_stack.pop(); } fn enter_inline_fragment( &mut self, _ctx: &mut ValidatorContext<'a>, _inline_fragment: &'a InlineFragment, ) { self.location_stack .push(__DirectiveLocation::INLINE_FRAGMENT); } fn exit_inline_fragment( &mut self, _ctx: &mut ValidatorContext<'a>, _inline_fragment: &'a InlineFragment, ) { self.location_stack.pop(); } }