Skip to main content

apollo_parser/parser/grammar/
operation.rs

1use crate::parser::grammar::directive;
2use crate::parser::grammar::name;
3use crate::parser::grammar::selection;
4use crate::parser::grammar::value::Constness;
5use crate::parser::grammar::variable;
6use crate::Parser;
7use crate::SyntaxKind;
8use crate::TokenKind;
9use crate::T;
10
11/// See: https://spec.graphql.org/October2021/#OperationDefinition
12///
13/// *OperationDefinition*:
14///    OperationType Name? VariableDefinitions? Directives? SelectionSet
15///    SelectionSet
16pub(crate) fn operation_definition(p: &mut Parser) {
17    match p.peek() {
18        Some(TokenKind::Name) => {
19            let _g = p.start_node(SyntaxKind::OPERATION_DEFINITION);
20
21            operation_type(p);
22
23            if let Some(TokenKind::Name) = p.peek() {
24                name::name(p);
25            }
26
27            if let Some(T!['(']) = p.peek() {
28                variable::variable_definitions(p)
29            }
30
31            if let Some(T![@]) = p.peek() {
32                directive::directives(p, Constness::NotConst);
33            }
34
35            match p.peek() {
36                Some(T!['{']) => selection::selection_set(p),
37                _ => p.err_and_pop("expected a Selection Set"),
38            }
39        }
40        Some(T!['{']) => {
41            let _g = p.start_node(SyntaxKind::OPERATION_DEFINITION);
42
43            selection::selection_set(p)
44        }
45        _ => p.err_and_pop("expected an Operation Type or a Selection Set"),
46    }
47}
48
49/// See: https://spec.graphql.org/October2021/#OperationType
50///
51/// *OperationType*: one of
52///    **query**    **mutation**    **subscription**
53pub(crate) fn operation_type(p: &mut Parser) {
54    if let Some(node) = p.peek_data() {
55        let _g = p.start_node(SyntaxKind::OPERATION_TYPE);
56        match node {
57            "query" => p.bump(SyntaxKind::query_KW),
58            "subscription" => p.bump(SyntaxKind::subscription_KW),
59            "mutation" => p.bump(SyntaxKind::mutation_KW),
60            _ => p.err_and_pop("expected either a 'mutation', a 'query', or a 'subscription'"),
61        }
62    }
63}
64
65#[cfg(test)]
66mod test {
67    use crate::Parser;
68
69    // NOTE @lrlna: related PR to the spec to avoid this issue:
70    // https://github.com/graphql/graphql-spec/pull/892
71    #[test]
72    fn it_continues_parsing_when_operation_definition_starts_with_description() {
73        let input = "\"description\"{}";
74        let parser = Parser::new(input);
75        let cst = parser.parse();
76
77        assert_eq!(cst.errors().len(), 2);
78        assert_eq!(cst.document().definitions().count(), 1);
79    }
80}