2020-05-09 09:55:04 +00:00
|
|
|
use crate::parser::ast::{OperationDefinition, VariableDefinition};
|
2020-03-24 10:54:22 +00:00
|
|
|
use crate::validation::visitor::{Visitor, VisitorContext};
|
2020-05-10 02:59:51 +00:00
|
|
|
use crate::Positioned;
|
2020-03-10 06:14:09 +00:00
|
|
|
use std::collections::HashSet;
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
pub struct UniqueVariableNames<'a> {
|
|
|
|
names: HashSet<&'a str>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Visitor<'a> for UniqueVariableNames<'a> {
|
|
|
|
fn enter_operation_definition(
|
|
|
|
&mut self,
|
2020-03-22 08:45:59 +00:00
|
|
|
_ctx: &mut VisitorContext<'a>,
|
2020-05-10 02:59:51 +00:00
|
|
|
_operation_definition: &'a Positioned<OperationDefinition>,
|
2020-03-10 06:14:09 +00:00
|
|
|
) {
|
|
|
|
self.names.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn enter_variable_definition(
|
|
|
|
&mut self,
|
2020-03-22 08:45:59 +00:00
|
|
|
ctx: &mut VisitorContext<'a>,
|
2020-05-10 02:59:51 +00:00
|
|
|
variable_definition: &'a Positioned<VariableDefinition>,
|
2020-03-10 06:14:09 +00:00
|
|
|
) {
|
2020-05-12 08:27:06 +00:00
|
|
|
if !self.names.insert(variable_definition.name.node) {
|
2020-03-10 06:14:09 +00:00
|
|
|
ctx.report_error(
|
2020-05-09 09:55:04 +00:00
|
|
|
vec![variable_definition.position()],
|
2020-03-10 06:14:09 +00:00
|
|
|
format!(
|
|
|
|
"There can only be one variable named \"${}\"",
|
|
|
|
variable_definition.name
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-05 08:00:26 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
use crate::validation::test_harness::{expect_fails_rule, expect_passes_rule};
|
|
|
|
|
|
|
|
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 }
|
|
|
|
"#,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|