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
use std::collections::HashSet; use crate::parser::types::{OperationDefinition, VariableDefinition}; use crate::validation::visitor::{Visitor, VisitorContext}; use crate::{Name, Positioned}; #[derive(Default)] pub struct UniqueVariableNames<'a> { names: HashSet<&'a str>, } impl<'a> Visitor<'a> for UniqueVariableNames<'a> { fn enter_operation_definition( &mut self, _ctx: &mut VisitorContext<'a>, _name: Option<&'a Name>, _operation_definition: &'a Positioned<OperationDefinition>, ) { self.names.clear(); } fn enter_variable_definition( &mut self, ctx: &mut VisitorContext<'a>, variable_definition: &'a Positioned<VariableDefinition>, ) { if !self.names.insert(&variable_definition.node.name.node) { ctx.report_error( vec![variable_definition.pos], format!( "There can only be one variable named \"${}\"", variable_definition.node.name.node ), ); } } } #[cfg(test)] mod tests { use super::*; pub fn factory<'a>() -> UniqueVariableNames<'a> { UniqueVariableNames::default() } #[test] fn unique_variable_names() { expect_passes_rule!( factory, r#" query A($x: Int, $y: String) { __typename } query B($x: String, $y: Int) { __typename } "#, ); } #[test] fn duplicate_variable_names() { expect_fails_rule!( factory, r#" query A($x: Int, $x: Int, $x: String) { __typename } query B($x: String, $x: Int) { __typename } query C($x: Int, $x: Int) { __typename } "#, ); } }