Skip to main content

apollo_parser/parser/grammar/
variable.rs

1use crate::parser::grammar::directive;
2use crate::parser::grammar::name;
3use crate::parser::grammar::ty;
4use crate::parser::grammar::value;
5use crate::parser::grammar::value::Constness;
6use crate::Parser;
7use crate::SyntaxKind;
8use crate::TokenKind;
9use crate::S;
10use crate::T;
11
12/// See: https://spec.graphql.org/October2021/#VariableDefinitions
13///
14/// *VariableDefinitions*:
15///     **(** VariableDefinition* **)**
16pub(crate) fn variable_definitions(p: &mut Parser) {
17    let _g = p.start_node(SyntaxKind::VARIABLE_DEFINITIONS);
18    p.bump(S!['(']);
19
20    if let Some(T![$]) = p.peek() {
21        variable_definition(p);
22    } else {
23        p.err("expected a Variable Definition")
24    }
25    p.peek_while_kind(T![$], variable_definition);
26
27    p.expect(T![')'], S![')']);
28}
29
30/// See: https://spec.graphql.org/October2021/#VariableDefinition
31///
32/// *VariableDefinition*:
33///     Variable **:** Type DefaultValue? Directives[Const]?
34pub(crate) fn variable_definition(p: &mut Parser) {
35    let _guard = p.start_node(SyntaxKind::VARIABLE_DEFINITION);
36    variable(p);
37
38    if let Some(T![:]) = p.peek() {
39        p.bump(S![:]);
40        if let Some(TokenKind::Name | TokenKind::LBracket) = p.peek() {
41            ty::ty(p);
42            if let Some(T![=]) = p.peek() {
43                value::default_value(p);
44            }
45            if let Some(T![@]) = p.peek() {
46                directive::directives(p, Constness::Const)
47            }
48        } else {
49            p.err("expected a Type");
50        }
51    } else {
52        p.err("expected a Name");
53    }
54}
55
56/// See: https://spec.graphql.org/October2021/#Variable
57///
58/// *Variable*:
59///     **$** Name
60pub(crate) fn variable(p: &mut Parser) {
61    let _g = p.start_node(SyntaxKind::VARIABLE);
62    p.bump(S![$]);
63    name::name(p);
64}
65
66#[cfg(test)]
67mod test {
68    use crate::cst;
69    use crate::Parser;
70
71    #[test]
72    fn it_accesses_variable_name_and_type() {
73        let gql = r#"
74query GroceryStoreTrip($budget: Int) {
75    name
76}
77        "#;
78
79        let parser = Parser::new(gql);
80        let cst = parser.parse();
81
82        assert!(cst.errors().len() == 0);
83
84        let doc = cst.document();
85
86        for definition in doc.definitions() {
87            if let cst::Definition::OperationDefinition(op_def) = definition {
88                for var in op_def
89                    .variable_definitions()
90                    .unwrap()
91                    .variable_definitions()
92                {
93                    assert_eq!(
94                        var.variable().unwrap().name().unwrap().text().as_ref(),
95                        "budget"
96                    );
97                    if let cst::Type::NamedType(name) = var.ty().unwrap() {
98                        assert_eq!(name.name().unwrap().text().as_ref(), "Int")
99                    }
100                }
101            }
102        }
103    }
104}