lang-graphql: add parser tests (#290)

Co-authored-by: Abhinav Gupta <127770473+abhinav-hasura@users.noreply.github.com>
V3_GIT_ORIGIN_REV_ID: d7b70a3cc70e6b9ead5867fd4b4fc56809878ebd
This commit is contained in:
Brandon Simmons 2024-01-30 12:41:48 -05:00 committed by hasura-bot
parent 82df77cd8e
commit 6c83ec7985
161 changed files with 7276 additions and 91 deletions

17
v3/Cargo.lock generated
View File

@ -880,6 +880,12 @@ dependencies = [
"generic-array",
]
[[package]]
name = "dissimilar"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632"
[[package]]
name = "dyn-clone"
version = "1.0.16"
@ -1011,6 +1017,16 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "expect-test"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3"
dependencies = [
"dissimilar",
"once_cell",
]
[[package]]
name = "fastrand"
version = "2.0.1"
@ -1669,6 +1685,7 @@ dependencies = [
"bson",
"criterion",
"diffy",
"expect-test",
"graphql-parser",
"http",
"human_bytes",

View File

@ -14,7 +14,7 @@ For local development, we use the reference agent implementation that is a part
To start the reference agent only, you can do:
```sh
docker-compose up reference_agent
docker compose up reference_agent
```
and point the host name `reference_agent` to localhost in your `/etc/hosts` file.

View File

@ -32,6 +32,7 @@ bson = "2.6.0"
bincode = "1.3.3"
human_bytes = "0.4.1"
diffy = "0.3.0"
expect-test = "1.4"
[[bench]]
name = "lexer"

View File

@ -37,7 +37,7 @@ pub fn bench_parser(c: &mut Criterion) {
group.bench_with_input(
BenchmarkId::new("hasura", query_name),
&query,
|b, query| b.iter(|| Parser::new(query).parse_executable_document()),
|b, query| b.iter(|| Parser::new(query).parse_executable_document().unwrap()),
);
}
group.finish();

View File

@ -21,6 +21,8 @@ pub enum ExecutableDefinition {
/// The operations of a GraphQL document.
///
/// There is either one anonymous operation or many named operations.
/// FIXME: I think we should use this? Then move the
/// lang-graphql/tests/query_testdata/ok/0001_empty test from 'ok' to 'err
// #[derive(Debug, Clone)]
// pub enum DocumentOperations {
// /// The document contains a single anonymous operation.

View File

@ -1,3 +1,5 @@
/// Lexer for both executable documents (i.e. graphql queries) and schema documents (SDL), which
/// share a common syntax
use std::fmt::Display;
use std::str::{from_utf8_unchecked, FromStr};
use std::{char, iter::Iterator};

View File

@ -29,6 +29,13 @@ pub enum Error {
/// when e.g. `"\l"` is parsed.
#[error("unknown escape sequence in string: {0:?}")]
UnknownEscapeSequence(String),
/// An invalid unicode escape sequence in a string literal was found, and
/// an error message is provided.
///
/// This began with `"\u"` being parsed and then something going wrong.
#[error("invalid unicode escape sequence in string. {0:?}")]
InvalidUnicodeEscapeSequence(String),
}
pub struct Consumed {
@ -232,10 +239,44 @@ fn parse_single_line_string(bytes: &[u8]) -> Result<(String, Consumed, usize), (
b'n' => ('\u{000A}', 1),
b'r' => ('\u{000D}', 1),
b't' => ('\u{0009}', 1),
// TODO, parse unicode escape sequences
// b'u' => {
// todo!()
// }
// unicode escape sequence:
b'u' => {
if i + 5 >= bytes.len() {
return Err((Error::Unterminated, Consumed::no_line_break(chars)));
}
// Collect the next 4 characters as hex digits
let hex_str = &bytes[i + 2..i + 6];
let hex = std::str::from_utf8(hex_str).map_err(|_| {
(
Error::InvalidUnicodeEscapeSequence(
"invalid format".to_string(),
),
Consumed::no_line_break(chars),
)
})?;
let code_point = u32::from_str_radix(hex, 16).map_err(|_| {
(
Error::InvalidUnicodeEscapeSequence(
"invalid hex digits".to_string(),
),
Consumed::no_line_break(chars),
)
})?;
let c = std::char::from_u32(code_point).ok_or_else(|| {
(
Error::InvalidUnicodeEscapeSequence(format!(
"0x{:X} is not a valid code point",
code_point
)),
Consumed::no_line_break(chars),
)
})?;
(c, 5) // 5 bytes consumed: u, and the 4 hex digits
}
b => {
return Err((
Error::UnknownEscapeSequence(format!("\\{b}")),

View File

@ -17,32 +17,35 @@ pub struct Parser<'a> {
}
#[derive(Error, Debug, PartialEq, Clone)]
pub struct Error {
expected_tokens: &'static [ExpectedToken],
found: TokenFound,
pub enum Error {
TokenError {
expected_tokens: &'static [ExpectedToken],
found: TokenFound,
},
/// For other parse errors, just supply an error message.
OtherError(&'static str),
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let expected_tokens = self
.expected_tokens
.iter()
.fold(String::new(), |acc, expected_token| {
acc + &expected_token.to_string() + ", "
});
let found = &self.found;
write!(
f,
"expected one of {expected_tokens}, but encountered: {found}"
)
}
}
impl Error {
pub fn new(expected_tokens: &'static [ExpectedToken], found: TokenFound) -> Self {
Error {
expected_tokens,
found,
match self {
Error::TokenError {
expected_tokens,
found,
} => {
let expected_tokens_str = expected_tokens
.iter()
.fold(String::new(), |acc, expected_token| {
acc + &expected_token.to_string() + ", "
});
write!(
f,
"expected one of {expected_tokens_str}, but encountered: {found}"
)
}
Error::OtherError(msg) => {
write!(f, "{}", msg)
}
}
}
}
@ -256,7 +259,10 @@ impl<'a> Parser<'a> {
fn eof<T>(&self, expected_tokens: &'static [ExpectedToken]) -> Result<T> {
Err(Positioned::new(
&self.lexer.get_position(),
Error::new(expected_tokens, TokenFound::EndOfFile),
Error::TokenError {
expected_tokens,
found: TokenFound::EndOfFile,
},
))
}
@ -266,18 +272,27 @@ impl<'a> Parser<'a> {
) -> Result<T> {
Err(Positioned::new(
&error.position,
Error::new(expected_tokens, TokenFound::LexerError(error.item.clone())),
Error::TokenError {
expected_tokens,
found: TokenFound::LexerError(error.item.clone()),
},
))
}
fn other_error<T>(error_msg: &'static str, start: SourcePosition) -> Result<T> {
Err(Positioned::new(&start, Error::OtherError(error_msg)))
}
fn unexpected_token<T>(
expected: &'static [ExpectedToken],
expected_tokens: &'static [ExpectedToken],
found: lexer::Token,
location: &SourcePosition,
) -> Result<T> {
Err(Positioned::new(
location,
Error::new(expected, TokenFound::Token(found)),
Error::TokenError {
expected_tokens,
found: TokenFound::Token(found),
},
))
}
@ -352,14 +367,48 @@ impl<'a> Parser<'a> {
Ok(items)
}
/// Parse delimited items into a `List`
/// <start> <item>* <end>
fn parse_delimited_list<T, F>(
/// Parse one or more delimited items into a `List`
/// <start> <item>+ <end>
///
/// This corresponds to occurrences of symbol plus the "LIST" subscript in the grammar given in
/// the spec. See:
/// https://spec.graphql.org/October2021/#sec-Grammar-Notation.Optionality-and-Lists
///
/// TODO Ideally return NonEmpty here
fn parse_nonempty_delimited_list<T, F>(
&mut self,
start_token: lexer::Punctuation,
end_token: lexer::Punctuation,
parse: F,
) -> Result<Spanning<Vec<T>>>
where
F: Fn(&mut Self) -> Result<T>,
{
self.parse_delimited_list_helper(start_token, end_token, parse, true)
}
/// Parse zero or more delimited items into a `List`
/// <start> <item>* <end>
fn parse_possibly_empty_delimited_list<T, F>(
&mut self,
start_token: lexer::Punctuation,
end_token: lexer::Punctuation,
parse: F,
) -> Result<Spanning<Vec<T>>>
where
F: Fn(&mut Self) -> Result<T>,
{
self.parse_delimited_list_helper(start_token, end_token, parse, false)
}
// NOTE: we'd like this to be private to this scope, but functionality is used in child
// modules.
fn parse_delimited_list_helper<T, F>(
&mut self,
start_token: lexer::Punctuation,
end_token: lexer::Punctuation,
parse: F,
must_be_nonempty: bool,
) -> Result<Spanning<Vec<T>>>
where
F: Fn(&mut Self) -> Result<T>,
{
@ -370,12 +419,17 @@ impl<'a> Parser<'a> {
items.push(parse(self)?);
}
let end = self.parse_punctuation(end_token)?;
if must_be_nonempty && items.is_empty() {
return Self::other_error("At least one item must be specified", end.start);
}
Ok(Spanning::start_end(start.start, end.end, items))
}
/// Parse optional delimited items into a `List`
/// (<start> <item>* <end>)?
fn parse_optional_delimited_list<T, F>(
/// Parse an optional delimited list of one or more items into a `List`
/// (<start> <item>+ <end>)?
///
/// TODO Ideally return NonEmpty here
fn parse_optional_nonempty_delimited_list<T, F>(
&mut self,
start_token: lexer::Punctuation,
end_token: lexer::Punctuation,
@ -385,10 +439,11 @@ impl<'a> Parser<'a> {
F: Fn(&mut Self) -> Result<T>,
{
if self.is_next_token(&lexer::Token::Punctuation(start_token.clone())) {
Ok(Some(self.parse_delimited_list(
Ok(Some(self.parse_delimited_list_helper(
start_token,
end_token,
parse,
true,
)?))
} else {
Ok(None)

View File

@ -36,10 +36,10 @@ impl<'a> Parser<'a> {
}
_ => Err(Positioned::new(
&token.start,
super::Error::new(
EXPECTED_TOKENS,
super::TokenFound::Token(token.item.clone()),
),
super::Error::TokenError {
expected_tokens: EXPECTED_TOKENS,
found: super::TokenFound::Token(token.item.clone()),
},
)),
},
}
@ -88,7 +88,7 @@ impl<'a> Parser<'a> {
pub fn parse_variable_definitions(
&mut self,
) -> super::Result<Option<Spanning<Vec<Spanning<VariableDefinition>>>>> {
self.parse_optional_delimited_list(
self.parse_optional_nonempty_delimited_list(
lexer::Punctuation::ParenL,
lexer::Punctuation::ParenR,
|s| s.parse_variable_definition(),
@ -129,19 +129,19 @@ impl<'a> Parser<'a> {
} else {
Err(Positioned::new(
&token.start,
super::Error::new(
EXPECTED_TOKENS,
super::TokenFound::Token(lexer::Token::Name(token.item)),
),
super::Error::TokenError {
expected_tokens: EXPECTED_TOKENS,
found: super::TokenFound::Token(lexer::Token::Name(token.item)),
},
))
}
}
_ => Err(Positioned::new(
&token.start,
super::Error::new(
EXPECTED_TOKENS,
super::TokenFound::Token(token.item.clone()),
),
super::Error::TokenError {
expected_tokens: EXPECTED_TOKENS,
found: super::TokenFound::Token(token.item.clone()),
},
)),
},
}
@ -162,10 +162,10 @@ impl<'a> Parser<'a> {
lexer::Token::Punctuation(lexer::Punctuation::BraceL) => Ok(None),
_ => Err(Positioned::new(
&token.start,
super::Error::new(
EXPECTED_TOKENS,
super::TokenFound::Token(token.item.clone()),
),
super::Error::TokenError {
expected_tokens: EXPECTED_TOKENS,
found: super::TokenFound::Token(token.item.clone()),
},
)),
},
}?;
@ -208,6 +208,7 @@ impl<'a> Parser<'a> {
))
}
}
// https://spec.graphql.org/October2021/#sec-Executable-Definitions
pub fn parse_executable_definition(&mut self) -> super::Result<Spanning<ExecutableDefinition>> {
static EXPECTED_TOKENS: &[super::ExpectedToken] = &[
super::ExpectedToken::Keyword(super::Keyword::Query),
@ -232,14 +233,15 @@ impl<'a> Parser<'a> {
}
_ => Err(Positioned::new(
&token.start,
super::Error::new(
EXPECTED_TOKENS,
super::TokenFound::Token(token.item.clone()),
),
super::Error::TokenError {
expected_tokens: EXPECTED_TOKENS,
found: super::TokenFound::Token(token.item.clone()),
},
)),
},
}
}
/// The top-level parser for a graphql request
pub fn parse_executable_document(&mut self) -> super::Result<ExecutableDocument> {
let mut items = vec![];
while self.peek().is_some() {

View File

@ -2,9 +2,18 @@ use super::Parser;
use crate::ast::{executable::FragmentDefinition, spanning::Spanning};
impl<'a> Parser<'a> {
// https://spec.graphql.org/October2021/#sec-Language.Fragments
pub fn parse_fragment(&mut self) -> super::Result<Spanning<FragmentDefinition>> {
let start_position = self.parse_keyword(&super::Keyword::Fragment)?.start;
let name = self.parse_name()?;
// It seems like this is in the spec to make parsing easier, or possibly unambiguous in the
// presence of directives?
if name.item.as_str() == "on" {
return Self::other_error(
"A fragment may not be named \"on\". Maybe you forgot the name?",
name.start,
);
}
let type_condition = self.parse_type_condition()?;
let directives = self.parse_directives()?;
let selection_set = self.parse_selection_set()?;

View File

@ -54,7 +54,7 @@ impl<'a> Parser<'a> {
let start_position =
get_start_position(&description, &self.parse_keyword(&super::Keyword::Schema)?);
let directives = self.parse_const_directives()?;
let operation_types = self.parse_delimited_list(
let operation_types = self.parse_nonempty_delimited_list(
lexer::Punctuation::BraceL,
lexer::Punctuation::BraceR,
|s| {
@ -103,7 +103,7 @@ impl<'a> Parser<'a> {
fn parse_const_arguments(
&mut self,
) -> super::Result<Option<Spanning<Vec<Spanning<InputValueDefinition>>>>> {
self.parse_optional_delimited_list(
self.parse_optional_nonempty_delimited_list(
lexer::Punctuation::ParenL,
lexer::Punctuation::ParenR,
|s| s.parse_input_value_definition(),
@ -163,7 +163,7 @@ impl<'a> Parser<'a> {
fn parse_fields_definition(
&mut self,
) -> super::Result<Spanning<Vec<Spanning<FieldDefinition>>>> {
self.parse_delimited_list(
self.parse_nonempty_delimited_list(
lexer::Punctuation::BraceL,
lexer::Punctuation::BraceR,
|s| s.parse_field_definition(),
@ -205,10 +205,10 @@ impl<'a> Parser<'a> {
}
_ => Err(Positioned::new(
&token.start,
super::Error::new(
EXPECTED_TOKENS,
super::TokenFound::Token(token.item.clone()),
),
super::Error::TokenError{
expected_tokens: EXPECTED_TOKENS,
found: super::TokenFound::Token(token.item.clone()),
},
)),
},
}
@ -302,10 +302,10 @@ impl<'a> Parser<'a> {
}
_ => Err(Positioned::new(
&token.start,
super::Error::new(
EXPECTED_TOKENS,
super::TokenFound::Token(token.item.clone()),
),
super::Error::TokenError {
expected_tokens: EXPECTED_TOKENS,
found: super::TokenFound::Token(token.item.clone()),
},
)),
},
}
@ -347,7 +347,7 @@ impl<'a> Parser<'a> {
get_start_position(&description, &self.parse_keyword(&super::Keyword::Enum)?);
let name = self.parse_name()?;
let directives = self.parse_const_directives()?;
let values = self.parse_delimited_list(
let values = self.parse_nonempty_delimited_list(
lexer::Punctuation::BraceL,
lexer::Punctuation::BraceR,
|s| {
@ -386,7 +386,7 @@ impl<'a> Parser<'a> {
get_start_position(&description, &self.parse_keyword(&super::Keyword::Input)?);
let name = self.parse_name()?;
let directives = self.parse_const_directives()?;
let fields = self.parse_delimited_list(
let fields = self.parse_nonempty_delimited_list(
lexer::Punctuation::BraceL,
lexer::Punctuation::BraceR,
|s| s.parse_input_value_definition(),
@ -447,18 +447,18 @@ impl<'a> Parser<'a> {
}
_ => Err(Positioned::new(
&token.start,
super::Error::new(
EXPECTED_TOKENS,
super::TokenFound::Token(token.item.clone()),
),
super::Error::TokenError {
expected_tokens: EXPECTED_TOKENS,
found: super::TokenFound::Token(token.item.clone()),
},
)),
},
_ => Err(Positioned::new(
&token.start,
super::Error::new(
EXPECTED_TOKENS,
super::TokenFound::Token(token.item.clone()),
),
super::Error::TokenError {
expected_tokens: EXPECTED_TOKENS,
found: super::TokenFound::Token(token.item.clone()),
},
)),
},
}

View File

@ -38,7 +38,7 @@ impl<'a> Parser<'a> {
}
pub fn parse_selection_set(&mut self) -> super::Result<Spanning<SelectionSet>> {
self.parse_delimited_list(
self.parse_nonempty_delimited_list(
lexer::Punctuation::BraceL,
lexer::Punctuation::BraceR,
|s| s.parse_selection(),
@ -122,7 +122,7 @@ impl<'a> Parser<'a> {
}
pub fn parse_arguments(&mut self) -> super::Result<Option<Spanning<Vec<Argument>>>> {
self.parse_optional_delimited_list(
self.parse_optional_nonempty_delimited_list(
lexer::Punctuation::ParenL,
lexer::Punctuation::ParenR,
|s| s.parse_key_value(|r| r.parse_value()),

View File

@ -104,7 +104,7 @@ impl<'a> Parser<'a> {
];
match self.peek_fail(EXPECTED_TOKENS)?.item {
lexer::Token::Punctuation(lexer::Punctuation::BracketL) => {
let list = self.parse_delimited_list(
let list = self.parse_possibly_empty_delimited_list(
lexer::Punctuation::BracketL,
lexer::Punctuation::BracketR,
|s| s.parse_const_value(),
@ -112,7 +112,7 @@ impl<'a> Parser<'a> {
Ok(list.map(ConstValue::List))
}
lexer::Token::Punctuation(lexer::Punctuation::BraceL) => {
let list = self.parse_delimited_list(
let list = self.parse_possibly_empty_delimited_list(
lexer::Punctuation::BraceL,
lexer::Punctuation::BraceR,
|s| s.parse_key_value(|r| r.parse_const_value()),
@ -149,7 +149,7 @@ impl<'a> Parser<'a> {
}
// [ (<value>,)* ]
lexer::Token::Punctuation(lexer::Punctuation::BracketL) => {
let list = self.parse_delimited_list(
let list = self.parse_possibly_empty_delimited_list(
lexer::Punctuation::BracketL,
lexer::Punctuation::BracketR,
|s| s.parse_value(),
@ -158,7 +158,7 @@ impl<'a> Parser<'a> {
}
// { (<key>: <value>,)* }
lexer::Token::Punctuation(lexer::Punctuation::BraceL) => {
let list = self.parse_delimited_list(
let list = self.parse_possibly_empty_delimited_list(
lexer::Punctuation::BraceL,
lexer::Punctuation::BraceR,
|s| s.parse_key_value(|r| r.parse_value()),

View File

@ -0,0 +1,7 @@
Copyright 2021 Apollo Graph, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,19 @@
- `testdata` contains snapshot/golden test inputs and expectations for SDL parsing
- `query_testdata` and `schema_data` were later added, but for
executable documents and SDL respectively. Theses cases were copied from the
apollo-rs project at 721e0753 and the license at `lang-graphql/tests/LICENSE-MIT`
applies to these. Cases added subsequently are licensed under this project's
top-level license.
- some cases from the apollo lexer tests are copied with a 9xxx prefix
- `schema_data` cases are currently unused (TODO if SDL parsing is important)
A few full `parse()` cases were also added from
[graphql-js tests](https://github.com/graphql/graphql-js/blob/main/src/language/__tests__/parser-test.ts)
although they were not numerous or very interesting. They are added starting at `ok/1111_*`
Some `ok` cases that are only valid for the 2021 spec were renamed to `*.2021` and ignored.
# TODO
- the `ok` case output mostly has not been audited
- We might port the old `testdata` cases to the framework taken from apollo since it is nicer.

View File

@ -1,8 +1,13 @@
use indexmap::IndexMap;
/// Test both schema and query parsing
use lang_graphql::parser;
use std::env;
use std::fs;
use std::io;
use std::path::PathBuf;
use std::{
env, fs,
path::{Path, PathBuf},
};
use expect_test::expect_file;
#[cfg(test)]
fn test_parser_for_schema(schema_path: PathBuf) -> Result<(), io::Error> {
@ -44,8 +49,10 @@ fn test_parser_for_schema(schema_path: PathBuf) -> Result<(), io::Error> {
Ok(())
}
/// Test SDL parsing. For each .graphql file with an accompanying .ast.txt file, make sure
/// parse_schema_document() of the former results in the latter.
#[test]
fn test_parser() -> Result<(), io::Error> {
fn test_schema_parser() -> Result<(), io::Error> {
let mut testdata = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
testdata.push("tests");
testdata.push("testdata");
@ -60,3 +67,141 @@ fn test_parser() -> Result<(), io::Error> {
}
Ok(())
}
#[test]
fn query_parser_wellformed_input_tests() {
dir_tests(&test_data_dir(), &["ok"], "txt", |text, path| {
let cst = parser::Parser::new(text).parse_executable_document();
assert_is_ok(&cst, path);
format!("{cst:#?}")
});
}
#[test]
fn query_parser_malformed_input_tests() {
dir_tests(&test_data_dir(), &["err"], "txt", |text, path| {
let cst = parser::Parser::new(text).parse_executable_document();
assert_is_err(&cst, path);
format!("{cst:#?}")
});
}
// -----------------------------------------------------------------------------------------------
// Code below was copied or adapted from the apollo-rs project at 721e0753 and the license at
// `lang-graphql/tests/LICENSE-MIT` applies.
/// Compares input code taken from a `.graphql` file in test_fixtures and its
/// expected output in the corresponding `.txt` file.
///
/// The test fails if the ouptut differs.
///
/// If a matching file does not exist, it will be created, filled with output,
/// but fail the test.
fn dir_tests<F>(test_data_dir: &Path, paths: &[&str], outfile_extension: &str, f: F)
where
F: Fn(&str, &Path) -> String,
{
for (path, input_code) in collect_graphql_files(test_data_dir, paths) {
let actual = f(&input_code, &path);
let path = path.with_extension(outfile_extension);
// TODO: we really want formatted output here, but:
// https://github.com/rust-analyzer/expect-test/issues/45
expect_file![path].assert_eq(&actual)
}
}
/// Collects all `.graphql` files from `dir` subdirectories defined by `paths`.
fn collect_graphql_files(root_dir: &Path, paths: &[&str]) -> Vec<(PathBuf, String)> {
paths
.iter()
.flat_map(|path| {
let path = root_dir.to_owned().join(path);
graphql_files_in_dir(&path).into_iter()
})
.map(|path| {
let text = fs::read_to_string(&path)
.unwrap_or_else(|_| panic!("File at {path:?} should be valid"));
(path, text)
})
.collect()
}
/// Collects paths to all `.graphql` files from `dir` in a sorted `Vec<PathBuf>`.
fn graphql_files_in_dir(dir: &Path) -> Vec<PathBuf> {
let mut paths = fs::read_dir(dir)
.unwrap()
.map(|file| {
let file = file?;
let path = file.path();
if path.extension().unwrap_or_default() == "graphql" {
Ok(Some(path))
} else {
Ok(None)
}
})
// Get rid of the `None`s
.filter_map(|result: std::io::Result<_>| result.transpose())
.collect::<Result<Vec<_>, _>>()
.unwrap();
paths.sort();
// Check for duplicate numbers.
let mut seen = IndexMap::new();
let next_number = paths.len() + 1;
for path in &paths {
let file_name = path.file_name().unwrap().to_string_lossy();
let (number, name): (usize, _) = match file_name.split_once('_') {
Some((number, name)) => match number.parse() {
Ok(number) => (number, name),
Err(err) => {
panic!("Invalid test file name: {path:?} does not start with a number ({err})")
}
},
None => panic!("Invalid test file name: {path:?} does not start with a number"),
};
if let Some(existing) = seen.get(&number) {
let suggest = dir.join(format!("{next_number:03}_{name}"));
panic!("Conflicting test file: {path:?} has the same number as {existing:?}. Suggested name: {suggest:?}");
}
seen.insert(number, path);
}
paths
}
/// PathBuf of test cases directory.
fn test_data_dir() -> PathBuf {
project_root().join("lang-graphql/tests/query_testdata")
}
/// project root.
fn project_root() -> PathBuf {
Path::new(
&env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
)
.ancestors()
.nth(1)
.unwrap()
.to_path_buf()
}
// Additional sanity checks to distinguish our error and success expectations:
fn assert_is_err<T: std::fmt::Debug>(actual: &parser::Result<T>, path: &Path) {
if actual.is_ok() {
println!("erroneously successful parse: {:?}", actual);
panic!(
"There should be errors in the file since this is an error case, but saw none in {:?}",
path.display()
);
}
}
fn assert_is_ok<T: std::fmt::Debug>(actual: &parser::Result<T>, path: &Path) {
if actual.is_err() {
println!("error: {:?}", actual);
panic!("There should be no errors in the file {:?}", path.display(),);
}
}

View File

@ -0,0 +1,3 @@
fragment on User @example {
id
}

View File

@ -0,0 +1,11 @@
Err(
Positioned {
item: OtherError(
"A fragment may not be named \"on\". Maybe you forgot the name?",
),
position: SourcePosition {
line: 1,
col: 10,
},
},
)

View File

@ -0,0 +1,3 @@
fragment friendFields User @example {
id
}

View File

@ -0,0 +1,22 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Keyword(
On,
),
],
found: Token(
Name(
Name(
"User",
),
),
),
},
position: SourcePosition {
line: 1,
col: 23,
},
},
)

View File

@ -0,0 +1 @@
fragment friendFields on User

View File

@ -0,0 +1,16 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Punctuation(
BraceL,
),
],
found: EndOfFile,
},
position: SourcePosition {
line: 1,
col: 30,
},
},
)

View File

@ -0,0 +1 @@
awsas8d2934213hkj0987

View File

@ -0,0 +1,28 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Keyword(
Query,
),
Keyword(
Mutation,
),
Keyword(
Subscription,
),
],
found: Token(
Name(
Name(
"awsas8d2934213hkj0987",
),
),
),
},
position: SourcePosition {
line: 1,
col: 1,
},
},
)

View File

@ -0,0 +1,6 @@
uasdf21230jkdw
{
pet
faveSnack
}

View File

@ -0,0 +1,28 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Keyword(
Query,
),
Keyword(
Mutation,
),
Keyword(
Subscription,
),
],
found: Token(
Name(
Name(
"uasdf21230jkdw",
),
),
),
},
position: SourcePosition {
line: 1,
col: 1,
},
},
)

View File

@ -0,0 +1,28 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Keyword(
Query,
),
Keyword(
Mutation,
),
Keyword(
Subscription,
),
],
found: Token(
Name(
Name(
"extend",
),
),
),
},
position: SourcePosition {
line: 1,
col: 1,
},
},
)

View File

@ -0,0 +1,11 @@
Err(
Positioned {
item: OtherError(
"At least one item must be specified",
),
position: SourcePosition {
line: 1,
col: 8,
},
},
)

View File

@ -0,0 +1,2 @@
"after this PR this should not be an issue: https://github.com/graphql/graphql-spec/pull/892"
query empty {}

View File

@ -0,0 +1,32 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Keyword(
Query,
),
Keyword(
Mutation,
),
Keyword(
Subscription,
),
Keyword(
Fragment,
),
Punctuation(
BraceL,
),
],
found: Token(
String(
"after this PR this should not be an issue: https://github.com/graphql/graphql-spec/pull/892",
),
),
},
position: SourcePosition {
line: 1,
col: 1,
},
},
)

View File

@ -0,0 +1,3 @@
{
user(id: "\string ID")
}

View File

@ -0,0 +1,39 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Number,
String,
Keyword(
True,
),
Keyword(
False,
),
Keyword(
Null,
),
Punctuation(
Dollar,
),
Punctuation(
BracketL,
),
Punctuation(
BraceL,
),
],
found: LexerError(
InvalidString(
UnknownEscapeSequence(
"\\115",
),
),
),
},
position: SourcePosition {
line: 2,
col: 13,
},
},
)

View File

@ -0,0 +1,7 @@
mutation {
createStore(draft: {
name: [{ locale: "en", value: "my store }]
}) {
name(locale: "en")
}
}

View File

@ -0,0 +1,37 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Number,
String,
Keyword(
True,
),
Keyword(
False,
),
Keyword(
Null,
),
Punctuation(
Dollar,
),
Punctuation(
BracketL,
),
Punctuation(
BraceL,
),
],
found: LexerError(
InvalidString(
Unterminated,
),
),
},
position: SourcePosition {
line: 3,
col: 47,
},
},
)

View File

@ -0,0 +1,20 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Punctuation(
BraceL,
),
],
found: Token(
Punctuation(
BraceR,
),
),
},
position: SourcePosition {
line: 1,
col: 18,
},
},
)

View File

@ -0,0 +1,16 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Punctuation(
BraceL,
),
],
found: EndOfFile,
},
position: SourcePosition {
line: 1,
col: 17,
},
},
)

View File

@ -0,0 +1 @@
{ inner { ... }}

View File

@ -0,0 +1,18 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Name,
],
found: Token(
Punctuation(
BraceR,
),
),
},
position: SourcePosition {
line: 1,
col: 15,
},
},
)

View File

@ -0,0 +1,3 @@
query Op() {
field
}

View File

@ -0,0 +1,11 @@
Err(
Positioned {
item: OtherError(
"At least one item must be specified",
),
position: SourcePosition {
line: 1,
col: 10,
},
},
)

View File

@ -0,0 +1,2 @@
# escape sequence not long enough (also make sure we don't read past end)
{ field(arg: "Has a \uA"

View File

@ -0,0 +1,37 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Number,
String,
Keyword(
True,
),
Keyword(
False,
),
Keyword(
Null,
),
Punctuation(
Dollar,
),
Punctuation(
BracketL,
),
Punctuation(
BraceL,
),
],
found: LexerError(
InvalidString(
Unterminated,
),
),
},
position: SourcePosition {
line: 2,
col: 21,
},
},
)

View File

@ -0,0 +1,2 @@
# Non-hex unicode escape
{ field(arg: "Has a \u0A0Z multi-byte character.") }

View File

@ -0,0 +1,39 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Number,
String,
Keyword(
True,
),
Keyword(
False,
),
Keyword(
Null,
),
Punctuation(
Dollar,
),
Punctuation(
BracketL,
),
Punctuation(
BraceL,
),
],
found: LexerError(
InvalidString(
InvalidUnicodeEscapeSequence(
"invalid hex digits",
),
),
),
},
position: SourcePosition {
line: 2,
col: 21,
},
},
)

View File

@ -0,0 +1,2 @@
# invalid code point unicode escape (reserved high surrogate)
{ field(arg: "Has a \uD801 multi-byte character.") }

View File

@ -0,0 +1,39 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Number,
String,
Keyword(
True,
),
Keyword(
False,
),
Keyword(
Null,
),
Punctuation(
Dollar,
),
Punctuation(
BracketL,
),
Punctuation(
BraceL,
),
],
found: LexerError(
InvalidString(
InvalidUnicodeEscapeSequence(
"0xD801 is not a valid code point",
),
),
),
},
position: SourcePosition {
line: 2,
col: 21,
},
},
)

View File

@ -0,0 +1,5 @@
{
sku: "\a invalidly escaped"
stringValue: "\"properly escaped\""
name: "\invalidly escaped\""
}

View File

@ -0,0 +1,20 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Name,
],
found: LexerError(
InvalidString(
UnknownEscapeSequence(
"\\97",
),
),
),
},
position: SourcePosition {
line: 2,
col: 11,
},
},
)

View File

@ -0,0 +1,7 @@
mutation {
createStore(draft: {
name: [{ locale: "en", value: "my store }]
}) {
name(locale: "en")
}
}

View File

@ -0,0 +1,37 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Number,
String,
Keyword(
True,
),
Keyword(
False,
),
Keyword(
Null,
),
Punctuation(
Dollar,
),
Punctuation(
BracketL,
),
Punctuation(
BraceL,
),
],
found: LexerError(
InvalidString(
Unterminated,
),
),
},
position: SourcePosition {
line: 3,
col: 47,
},
},
)

View File

@ -0,0 +1,5 @@
mutation {
createstore {
name(locale: "en)
}
}

View File

@ -0,0 +1,37 @@
Err(
Positioned {
item: TokenError {
expected_tokens: [
Number,
String,
Keyword(
True,
),
Keyword(
False,
),
Keyword(
Null,
),
Punctuation(
Dollar,
),
Punctuation(
BracketL,
),
Punctuation(
BraceL,
),
],
found: LexerError(
InvalidString(
Unterminated,
),
),
},
position: SourcePosition {
line: 3,
col: 22,
},
},
)

View File

@ -0,0 +1,5 @@
Ok(
ExecutableDocument {
items: [],
},
)

View File

@ -0,0 +1,4 @@
{
pet
faveSnack
}

View File

@ -0,0 +1,100 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"pet",
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 7,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 7,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"faveSnack",
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 13,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 13,
},
},
],
},
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 4,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 4,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,15 @@
{
pet {
name
birthday {
month
day
}
playmates {
name
faveSnack
}
}
faveSnack
}

View File

@ -0,0 +1,362 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"pet",
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 7,
},
},
arguments: None,
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"name",
),
start: SourcePosition {
line: 4,
col: 9,
},
end: SourcePosition {
line: 4,
col: 12,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 4,
col: 9,
},
end: SourcePosition {
line: 4,
col: 12,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"birthday",
),
start: SourcePosition {
line: 5,
col: 9,
},
end: SourcePosition {
line: 5,
col: 16,
},
},
arguments: None,
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"month",
),
start: SourcePosition {
line: 6,
col: 13,
},
end: SourcePosition {
line: 6,
col: 17,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 6,
col: 13,
},
end: SourcePosition {
line: 6,
col: 17,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"day",
),
start: SourcePosition {
line: 7,
col: 13,
},
end: SourcePosition {
line: 7,
col: 15,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 7,
col: 13,
},
end: SourcePosition {
line: 7,
col: 15,
},
},
],
},
start: SourcePosition {
line: 5,
col: 18,
},
end: SourcePosition {
line: 8,
col: 9,
},
},
),
},
),
start: SourcePosition {
line: 5,
col: 9,
},
end: SourcePosition {
line: 5,
col: 16,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"playmates",
),
start: SourcePosition {
line: 9,
col: 9,
},
end: SourcePosition {
line: 9,
col: 17,
},
},
arguments: None,
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"name",
),
start: SourcePosition {
line: 10,
col: 13,
},
end: SourcePosition {
line: 10,
col: 16,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 10,
col: 13,
},
end: SourcePosition {
line: 10,
col: 16,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"faveSnack",
),
start: SourcePosition {
line: 11,
col: 13,
},
end: SourcePosition {
line: 11,
col: 21,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 11,
col: 13,
},
end: SourcePosition {
line: 11,
col: 21,
},
},
],
},
start: SourcePosition {
line: 9,
col: 19,
},
end: SourcePosition {
line: 12,
col: 9,
},
},
),
},
),
start: SourcePosition {
line: 9,
col: 9,
},
end: SourcePosition {
line: 9,
col: 17,
},
},
],
},
start: SourcePosition {
line: 3,
col: 9,
},
end: SourcePosition {
line: 13,
col: 5,
},
},
),
},
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 7,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"faveSnack",
),
start: SourcePosition {
line: 14,
col: 5,
},
end: SourcePosition {
line: 14,
col: 13,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 14,
col: 5,
},
end: SourcePosition {
line: 14,
col: 13,
},
},
],
},
start: SourcePosition {
line: 2,
col: 1,
},
end: SourcePosition {
line: 15,
col: 1,
},
},
},
),
start: SourcePosition {
line: 2,
col: 1,
},
end: SourcePosition {
line: 15,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,15 @@
{
pet {
name: nickname
birthday {
month
day
}
playmates {
name
faveSnack
}
}
faveSnack(quantity: 4)
}

View File

@ -0,0 +1,431 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"pet",
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 7,
},
},
arguments: None,
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: Some(
Spanning {
item: Alias(
Name(
"name",
),
),
start: SourcePosition {
line: 4,
col: 9,
},
end: SourcePosition {
line: 4,
col: 12,
},
},
),
name: Spanning {
item: Name(
"nickname",
),
start: SourcePosition {
line: 4,
col: 15,
},
end: SourcePosition {
line: 4,
col: 22,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 4,
col: 15,
},
end: SourcePosition {
line: 4,
col: 22,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"birthday",
),
start: SourcePosition {
line: 5,
col: 9,
},
end: SourcePosition {
line: 5,
col: 16,
},
},
arguments: None,
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"month",
),
start: SourcePosition {
line: 6,
col: 13,
},
end: SourcePosition {
line: 6,
col: 17,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 6,
col: 13,
},
end: SourcePosition {
line: 6,
col: 17,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"day",
),
start: SourcePosition {
line: 7,
col: 13,
},
end: SourcePosition {
line: 7,
col: 15,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 7,
col: 13,
},
end: SourcePosition {
line: 7,
col: 15,
},
},
],
},
start: SourcePosition {
line: 5,
col: 18,
},
end: SourcePosition {
line: 8,
col: 9,
},
},
),
},
),
start: SourcePosition {
line: 5,
col: 9,
},
end: SourcePosition {
line: 5,
col: 16,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"playmates",
),
start: SourcePosition {
line: 9,
col: 9,
},
end: SourcePosition {
line: 9,
col: 17,
},
},
arguments: None,
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"name",
),
start: SourcePosition {
line: 10,
col: 13,
},
end: SourcePosition {
line: 10,
col: 16,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 10,
col: 13,
},
end: SourcePosition {
line: 10,
col: 16,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"faveSnack",
),
start: SourcePosition {
line: 11,
col: 13,
},
end: SourcePosition {
line: 11,
col: 21,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 11,
col: 13,
},
end: SourcePosition {
line: 11,
col: 21,
},
},
],
},
start: SourcePosition {
line: 9,
col: 19,
},
end: SourcePosition {
line: 12,
col: 9,
},
},
),
},
),
start: SourcePosition {
line: 9,
col: 9,
},
end: SourcePosition {
line: 9,
col: 17,
},
},
],
},
start: SourcePosition {
line: 3,
col: 9,
},
end: SourcePosition {
line: 13,
col: 5,
},
},
),
},
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 7,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"faveSnack",
),
start: SourcePosition {
line: 14,
col: 5,
},
end: SourcePosition {
line: 14,
col: 13,
},
},
arguments: Some(
Spanning {
item: [
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"quantity",
),
start: SourcePosition {
line: 14,
col: 15,
},
end: SourcePosition {
line: 14,
col: 22,
},
},
value: Spanning {
item: SimpleValue(
Integer(
4,
),
),
start: SourcePosition {
line: 14,
col: 25,
},
end: SourcePosition {
line: 14,
col: 25,
},
},
},
start: SourcePosition {
line: 14,
col: 15,
},
end: SourcePosition {
line: 14,
col: 25,
},
},
],
start: SourcePosition {
line: 14,
col: 14,
},
end: SourcePosition {
line: 14,
col: 26,
},
},
),
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 14,
col: 5,
},
end: SourcePosition {
line: 14,
col: 13,
},
},
],
},
start: SourcePosition {
line: 2,
col: 1,
},
end: SourcePosition {
line: 15,
col: 1,
},
},
},
),
start: SourcePosition {
line: 2,
col: 1,
},
end: SourcePosition {
line: 15,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,9 @@
{
animal
faveSnack
... on Pet {
playmates {
count
}
}
}

View File

@ -0,0 +1,235 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"animal",
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 10,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 10,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"faveSnack",
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 13,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 13,
},
},
Spanning {
item: InlineFragment(
InlineFragment {
type_condition: Some(
Spanning {
item: TypeCondition {
on: Spanning {
item: TypeName(
Name(
"Pet",
),
),
start: SourcePosition {
line: 4,
col: 12,
},
end: SourcePosition {
line: 4,
col: 14,
},
},
},
start: SourcePosition {
line: 4,
col: 9,
},
end: SourcePosition {
line: 4,
col: 14,
},
},
),
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"playmates",
),
start: SourcePosition {
line: 5,
col: 7,
},
end: SourcePosition {
line: 5,
col: 15,
},
},
arguments: None,
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"count",
),
start: SourcePosition {
line: 6,
col: 9,
},
end: SourcePosition {
line: 6,
col: 13,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 6,
col: 9,
},
end: SourcePosition {
line: 6,
col: 13,
},
},
],
},
start: SourcePosition {
line: 5,
col: 17,
},
end: SourcePosition {
line: 7,
col: 7,
},
},
),
},
),
start: SourcePosition {
line: 5,
col: 7,
},
end: SourcePosition {
line: 5,
col: 15,
},
},
],
},
start: SourcePosition {
line: 4,
col: 16,
},
end: SourcePosition {
line: 8,
col: 5,
},
},
},
),
start: SourcePosition {
line: 4,
col: 5,
},
end: SourcePosition {
line: 8,
col: 5,
},
},
],
},
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 9,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 9,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,15 @@
{
pet
...snackSelection
... on Nap {
cozyLocation
durationOfNap
}
...snackSelection @deprecated
... on Nap @provides(duration: "2 hours") {
cozyLocation
}
... @J(N: 0) {
a
}
}

View File

@ -0,0 +1,582 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"pet",
),
start: SourcePosition {
line: 2,
col: 3,
},
end: SourcePosition {
line: 2,
col: 5,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 3,
},
end: SourcePosition {
line: 2,
col: 5,
},
},
Spanning {
item: FragmentSpread(
FragmentSpread {
fragment_name: Spanning {
item: Name(
"snackSelection",
),
start: SourcePosition {
line: 3,
col: 6,
},
end: SourcePosition {
line: 3,
col: 19,
},
},
directives: [],
},
),
start: SourcePosition {
line: 3,
col: 3,
},
end: SourcePosition {
line: 3,
col: 19,
},
},
Spanning {
item: InlineFragment(
InlineFragment {
type_condition: Some(
Spanning {
item: TypeCondition {
on: Spanning {
item: TypeName(
Name(
"Nap",
),
),
start: SourcePosition {
line: 4,
col: 10,
},
end: SourcePosition {
line: 4,
col: 12,
},
},
},
start: SourcePosition {
line: 4,
col: 7,
},
end: SourcePosition {
line: 4,
col: 12,
},
},
),
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"cozyLocation",
),
start: SourcePosition {
line: 5,
col: 5,
},
end: SourcePosition {
line: 5,
col: 16,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 5,
col: 5,
},
end: SourcePosition {
line: 5,
col: 16,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"durationOfNap",
),
start: SourcePosition {
line: 6,
col: 5,
},
end: SourcePosition {
line: 6,
col: 17,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 6,
col: 5,
},
end: SourcePosition {
line: 6,
col: 17,
},
},
],
},
start: SourcePosition {
line: 4,
col: 14,
},
end: SourcePosition {
line: 7,
col: 3,
},
},
},
),
start: SourcePosition {
line: 4,
col: 3,
},
end: SourcePosition {
line: 7,
col: 3,
},
},
Spanning {
item: FragmentSpread(
FragmentSpread {
fragment_name: Spanning {
item: Name(
"snackSelection",
),
start: SourcePosition {
line: 8,
col: 6,
},
end: SourcePosition {
line: 8,
col: 19,
},
},
directives: [
Spanning {
item: Directive {
name: Spanning {
item: Name(
"deprecated",
),
start: SourcePosition {
line: 8,
col: 22,
},
end: SourcePosition {
line: 8,
col: 31,
},
},
arguments: None,
},
start: SourcePosition {
line: 8,
col: 21,
},
end: SourcePosition {
line: 8,
col: 31,
},
},
],
},
),
start: SourcePosition {
line: 8,
col: 3,
},
end: SourcePosition {
line: 8,
col: 19,
},
},
Spanning {
item: InlineFragment(
InlineFragment {
type_condition: Some(
Spanning {
item: TypeCondition {
on: Spanning {
item: TypeName(
Name(
"Nap",
),
),
start: SourcePosition {
line: 9,
col: 10,
},
end: SourcePosition {
line: 9,
col: 12,
},
},
},
start: SourcePosition {
line: 9,
col: 7,
},
end: SourcePosition {
line: 9,
col: 12,
},
},
),
directives: [
Spanning {
item: Directive {
name: Spanning {
item: Name(
"provides",
),
start: SourcePosition {
line: 9,
col: 15,
},
end: SourcePosition {
line: 9,
col: 22,
},
},
arguments: Some(
Spanning {
item: [
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"duration",
),
start: SourcePosition {
line: 9,
col: 24,
},
end: SourcePosition {
line: 9,
col: 31,
},
},
value: Spanning {
item: SimpleValue(
String(
"2 hours",
),
),
start: SourcePosition {
line: 9,
col: 34,
},
end: SourcePosition {
line: 9,
col: 42,
},
},
},
start: SourcePosition {
line: 9,
col: 24,
},
end: SourcePosition {
line: 9,
col: 42,
},
},
],
start: SourcePosition {
line: 9,
col: 23,
},
end: SourcePosition {
line: 9,
col: 43,
},
},
),
},
start: SourcePosition {
line: 9,
col: 14,
},
end: SourcePosition {
line: 9,
col: 43,
},
},
],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"cozyLocation",
),
start: SourcePosition {
line: 10,
col: 5,
},
end: SourcePosition {
line: 10,
col: 16,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 10,
col: 5,
},
end: SourcePosition {
line: 10,
col: 16,
},
},
],
},
start: SourcePosition {
line: 9,
col: 45,
},
end: SourcePosition {
line: 11,
col: 3,
},
},
},
),
start: SourcePosition {
line: 9,
col: 3,
},
end: SourcePosition {
line: 11,
col: 3,
},
},
Spanning {
item: InlineFragment(
InlineFragment {
type_condition: None,
directives: [
Spanning {
item: Directive {
name: Spanning {
item: Name(
"J",
),
start: SourcePosition {
line: 12,
col: 8,
},
end: SourcePosition {
line: 12,
col: 8,
},
},
arguments: Some(
Spanning {
item: [
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"N",
),
start: SourcePosition {
line: 12,
col: 10,
},
end: SourcePosition {
line: 12,
col: 10,
},
},
value: Spanning {
item: SimpleValue(
Integer(
0,
),
),
start: SourcePosition {
line: 12,
col: 13,
},
end: SourcePosition {
line: 12,
col: 13,
},
},
},
start: SourcePosition {
line: 12,
col: 10,
},
end: SourcePosition {
line: 12,
col: 13,
},
},
],
start: SourcePosition {
line: 12,
col: 9,
},
end: SourcePosition {
line: 12,
col: 14,
},
},
),
},
start: SourcePosition {
line: 12,
col: 7,
},
end: SourcePosition {
line: 12,
col: 14,
},
},
],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"a",
),
start: SourcePosition {
line: 13,
col: 5,
},
end: SourcePosition {
line: 13,
col: 5,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 13,
col: 5,
},
end: SourcePosition {
line: 13,
col: 5,
},
},
],
},
start: SourcePosition {
line: 12,
col: 16,
},
end: SourcePosition {
line: 14,
col: 3,
},
},
},
),
start: SourcePosition {
line: 12,
col: 3,
},
end: SourcePosition {
line: 14,
col: 3,
},
},
],
},
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 15,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 15,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,5 @@
fragment friendFields on User @example {
id
name
profilePic(size: 50)
}

View File

@ -0,0 +1,248 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Fragment(
FragmentDefinition {
name: Spanning {
item: Name(
"friendFields",
),
start: SourcePosition {
line: 1,
col: 10,
},
end: SourcePosition {
line: 1,
col: 21,
},
},
type_condition: Spanning {
item: TypeCondition {
on: Spanning {
item: TypeName(
Name(
"User",
),
),
start: SourcePosition {
line: 1,
col: 26,
},
end: SourcePosition {
line: 1,
col: 29,
},
},
},
start: SourcePosition {
line: 1,
col: 23,
},
end: SourcePosition {
line: 1,
col: 29,
},
},
directives: [
Spanning {
item: Directive {
name: Spanning {
item: Name(
"example",
),
start: SourcePosition {
line: 1,
col: 32,
},
end: SourcePosition {
line: 1,
col: 38,
},
},
arguments: None,
},
start: SourcePosition {
line: 1,
col: 31,
},
end: SourcePosition {
line: 1,
col: 38,
},
},
],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"id",
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 6,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 6,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"name",
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 8,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 8,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"profilePic",
),
start: SourcePosition {
line: 4,
col: 5,
},
end: SourcePosition {
line: 4,
col: 14,
},
},
arguments: Some(
Spanning {
item: [
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"size",
),
start: SourcePosition {
line: 4,
col: 16,
},
end: SourcePosition {
line: 4,
col: 19,
},
},
value: Spanning {
item: SimpleValue(
Integer(
50,
),
),
start: SourcePosition {
line: 4,
col: 22,
},
end: SourcePosition {
line: 4,
col: 23,
},
},
},
start: SourcePosition {
line: 4,
col: 16,
},
end: SourcePosition {
line: 4,
col: 23,
},
},
],
start: SourcePosition {
line: 4,
col: 15,
},
end: SourcePosition {
line: 4,
col: 24,
},
},
),
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 4,
col: 5,
},
end: SourcePosition {
line: 4,
col: 14,
},
},
],
},
start: SourcePosition {
line: 1,
col: 40,
},
end: SourcePosition {
line: 5,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 5,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,5 @@
fragment friendFields on User {
id
name
...standardProfilePic
}

View File

@ -0,0 +1,165 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Fragment(
FragmentDefinition {
name: Spanning {
item: Name(
"friendFields",
),
start: SourcePosition {
line: 1,
col: 10,
},
end: SourcePosition {
line: 1,
col: 21,
},
},
type_condition: Spanning {
item: TypeCondition {
on: Spanning {
item: TypeName(
Name(
"User",
),
),
start: SourcePosition {
line: 1,
col: 26,
},
end: SourcePosition {
line: 1,
col: 29,
},
},
},
start: SourcePosition {
line: 1,
col: 23,
},
end: SourcePosition {
line: 1,
col: 29,
},
},
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"id",
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 6,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 6,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"name",
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 8,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 8,
},
},
Spanning {
item: FragmentSpread(
FragmentSpread {
fragment_name: Spanning {
item: Name(
"standardProfilePic",
),
start: SourcePosition {
line: 4,
col: 8,
},
end: SourcePosition {
line: 4,
col: 25,
},
},
directives: [],
},
),
start: SourcePosition {
line: 4,
col: 5,
},
end: SourcePosition {
line: 4,
col: 25,
},
},
],
},
start: SourcePosition {
line: 1,
col: 31,
},
end: SourcePosition {
line: 5,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 5,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,9 @@
query myQuery {
animal: cat
dog {
panda {
anotherCat @deprecated
}
}
lion
}

View File

@ -0,0 +1,280 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: Some(
Spanning {
item: Name(
"myQuery",
),
start: SourcePosition {
line: 1,
col: 7,
},
end: SourcePosition {
line: 1,
col: 13,
},
},
),
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: Some(
Spanning {
item: Alias(
Name(
"animal",
),
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 10,
},
},
),
name: Spanning {
item: Name(
"cat",
),
start: SourcePosition {
line: 2,
col: 13,
},
end: SourcePosition {
line: 2,
col: 15,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 13,
},
end: SourcePosition {
line: 2,
col: 15,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"dog",
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 7,
},
},
arguments: None,
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"panda",
),
start: SourcePosition {
line: 4,
col: 9,
},
end: SourcePosition {
line: 4,
col: 13,
},
},
arguments: None,
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"anotherCat",
),
start: SourcePosition {
line: 5,
col: 13,
},
end: SourcePosition {
line: 5,
col: 22,
},
},
arguments: None,
directives: [
Spanning {
item: Directive {
name: Spanning {
item: Name(
"deprecated",
),
start: SourcePosition {
line: 5,
col: 25,
},
end: SourcePosition {
line: 5,
col: 34,
},
},
arguments: None,
},
start: SourcePosition {
line: 5,
col: 24,
},
end: SourcePosition {
line: 5,
col: 34,
},
},
],
selection_set: None,
},
),
start: SourcePosition {
line: 5,
col: 13,
},
end: SourcePosition {
line: 5,
col: 22,
},
},
],
},
start: SourcePosition {
line: 4,
col: 15,
},
end: SourcePosition {
line: 6,
col: 9,
},
},
),
},
),
start: SourcePosition {
line: 4,
col: 9,
},
end: SourcePosition {
line: 4,
col: 13,
},
},
],
},
start: SourcePosition {
line: 3,
col: 9,
},
end: SourcePosition {
line: 7,
col: 5,
},
},
),
},
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 7,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"lion",
),
start: SourcePosition {
line: 8,
col: 5,
},
end: SourcePosition {
line: 8,
col: 8,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 8,
col: 5,
},
end: SourcePosition {
line: 8,
col: 8,
},
},
],
},
start: SourcePosition {
line: 1,
col: 15,
},
end: SourcePosition {
line: 9,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 9,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,4 @@
query myQuery($var: input $varOther: otherInput){
animal
treat
}

View File

@ -0,0 +1,219 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: Some(
Spanning {
item: Name(
"myQuery",
),
start: SourcePosition {
line: 1,
col: 7,
},
end: SourcePosition {
line: 1,
col: 13,
},
},
),
variable_definitions: Some(
Spanning {
item: [
Spanning {
item: VariableDefinition {
name: Spanning {
item: Name(
"var",
),
start: SourcePosition {
line: 1,
col: 16,
},
end: SourcePosition {
line: 1,
col: 18,
},
},
var_type: Spanning {
item: TypeContainer {
base: Named(
TypeName(
Name(
"input",
),
),
),
nullable: true,
},
start: SourcePosition {
line: 1,
col: 21,
},
end: SourcePosition {
line: 1,
col: 25,
},
},
default_value: None,
},
start: SourcePosition {
line: 1,
col: 15,
},
end: SourcePosition {
line: 1,
col: 25,
},
},
Spanning {
item: VariableDefinition {
name: Spanning {
item: Name(
"varOther",
),
start: SourcePosition {
line: 1,
col: 28,
},
end: SourcePosition {
line: 1,
col: 35,
},
},
var_type: Spanning {
item: TypeContainer {
base: Named(
TypeName(
Name(
"otherInput",
),
),
),
nullable: true,
},
start: SourcePosition {
line: 1,
col: 38,
},
end: SourcePosition {
line: 1,
col: 47,
},
},
default_value: None,
},
start: SourcePosition {
line: 1,
col: 27,
},
end: SourcePosition {
line: 1,
col: 47,
},
},
],
start: SourcePosition {
line: 1,
col: 14,
},
end: SourcePosition {
line: 1,
col: 48,
},
},
),
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"animal",
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 10,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 10,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"treat",
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 9,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 9,
},
},
],
},
start: SourcePosition {
line: 1,
col: 49,
},
end: SourcePosition {
line: 4,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 4,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,4 @@
query myQuery($var: input $varOther: otherInput) @deprecated @unused {
animal
treat
}

View File

@ -0,0 +1,272 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: Some(
Spanning {
item: Name(
"myQuery",
),
start: SourcePosition {
line: 1,
col: 7,
},
end: SourcePosition {
line: 1,
col: 13,
},
},
),
variable_definitions: Some(
Spanning {
item: [
Spanning {
item: VariableDefinition {
name: Spanning {
item: Name(
"var",
),
start: SourcePosition {
line: 1,
col: 16,
},
end: SourcePosition {
line: 1,
col: 18,
},
},
var_type: Spanning {
item: TypeContainer {
base: Named(
TypeName(
Name(
"input",
),
),
),
nullable: true,
},
start: SourcePosition {
line: 1,
col: 21,
},
end: SourcePosition {
line: 1,
col: 25,
},
},
default_value: None,
},
start: SourcePosition {
line: 1,
col: 15,
},
end: SourcePosition {
line: 1,
col: 25,
},
},
Spanning {
item: VariableDefinition {
name: Spanning {
item: Name(
"varOther",
),
start: SourcePosition {
line: 1,
col: 28,
},
end: SourcePosition {
line: 1,
col: 35,
},
},
var_type: Spanning {
item: TypeContainer {
base: Named(
TypeName(
Name(
"otherInput",
),
),
),
nullable: true,
},
start: SourcePosition {
line: 1,
col: 38,
},
end: SourcePosition {
line: 1,
col: 47,
},
},
default_value: None,
},
start: SourcePosition {
line: 1,
col: 27,
},
end: SourcePosition {
line: 1,
col: 47,
},
},
],
start: SourcePosition {
line: 1,
col: 14,
},
end: SourcePosition {
line: 1,
col: 48,
},
},
),
directives: [
Spanning {
item: Directive {
name: Spanning {
item: Name(
"deprecated",
),
start: SourcePosition {
line: 1,
col: 51,
},
end: SourcePosition {
line: 1,
col: 60,
},
},
arguments: None,
},
start: SourcePosition {
line: 1,
col: 50,
},
end: SourcePosition {
line: 1,
col: 60,
},
},
Spanning {
item: Directive {
name: Spanning {
item: Name(
"unused",
),
start: SourcePosition {
line: 1,
col: 63,
},
end: SourcePosition {
line: 1,
col: 68,
},
},
arguments: None,
},
start: SourcePosition {
line: 1,
col: 62,
},
end: SourcePosition {
line: 1,
col: 68,
},
},
],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"animal",
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 10,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 10,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"treat",
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 9,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 9,
},
},
],
},
start: SourcePosition {
line: 1,
col: 70,
},
end: SourcePosition {
line: 4,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 4,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,11 @@
{
user(
id: 4,
size: $size
value: "string",
input: [ "one", 1.34 ],
otherInput: { key: false, output: null }
emptyList: []
emptyObject: {}
)
}

View File

@ -0,0 +1,464 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"user",
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 8,
},
},
arguments: Some(
Spanning {
item: [
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"id",
),
start: SourcePosition {
line: 3,
col: 9,
},
end: SourcePosition {
line: 3,
col: 10,
},
},
value: Spanning {
item: SimpleValue(
Integer(
4,
),
),
start: SourcePosition {
line: 3,
col: 13,
},
end: SourcePosition {
line: 3,
col: 13,
},
},
},
start: SourcePosition {
line: 3,
col: 9,
},
end: SourcePosition {
line: 3,
col: 13,
},
},
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"size",
),
start: SourcePosition {
line: 4,
col: 9,
},
end: SourcePosition {
line: 4,
col: 12,
},
},
value: Spanning {
item: Variable(
Name(
"size",
),
),
start: SourcePosition {
line: 4,
col: 15,
},
end: SourcePosition {
line: 4,
col: 19,
},
},
},
start: SourcePosition {
line: 4,
col: 9,
},
end: SourcePosition {
line: 4,
col: 19,
},
},
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"value",
),
start: SourcePosition {
line: 5,
col: 9,
},
end: SourcePosition {
line: 5,
col: 13,
},
},
value: Spanning {
item: SimpleValue(
String(
"string",
),
),
start: SourcePosition {
line: 5,
col: 16,
},
end: SourcePosition {
line: 5,
col: 23,
},
},
},
start: SourcePosition {
line: 5,
col: 9,
},
end: SourcePosition {
line: 5,
col: 23,
},
},
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"input",
),
start: SourcePosition {
line: 6,
col: 9,
},
end: SourcePosition {
line: 6,
col: 13,
},
},
value: Spanning {
item: List(
[
Spanning {
item: SimpleValue(
String(
"one",
),
),
start: SourcePosition {
line: 6,
col: 18,
},
end: SourcePosition {
line: 6,
col: 22,
},
},
Spanning {
item: SimpleValue(
Float(
1.34,
),
),
start: SourcePosition {
line: 6,
col: 25,
},
end: SourcePosition {
line: 6,
col: 28,
},
},
],
),
start: SourcePosition {
line: 6,
col: 16,
},
end: SourcePosition {
line: 6,
col: 30,
},
},
},
start: SourcePosition {
line: 6,
col: 9,
},
end: SourcePosition {
line: 6,
col: 30,
},
},
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"otherInput",
),
start: SourcePosition {
line: 7,
col: 9,
},
end: SourcePosition {
line: 7,
col: 18,
},
},
value: Spanning {
item: Object(
[
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"key",
),
start: SourcePosition {
line: 7,
col: 23,
},
end: SourcePosition {
line: 7,
col: 25,
},
},
value: Spanning {
item: SimpleValue(
Boolean(
false,
),
),
start: SourcePosition {
line: 7,
col: 28,
},
end: SourcePosition {
line: 7,
col: 32,
},
},
},
start: SourcePosition {
line: 7,
col: 23,
},
end: SourcePosition {
line: 7,
col: 32,
},
},
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"output",
),
start: SourcePosition {
line: 7,
col: 35,
},
end: SourcePosition {
line: 7,
col: 40,
},
},
value: Spanning {
item: SimpleValue(
Null,
),
start: SourcePosition {
line: 7,
col: 43,
},
end: SourcePosition {
line: 7,
col: 46,
},
},
},
start: SourcePosition {
line: 7,
col: 35,
},
end: SourcePosition {
line: 7,
col: 46,
},
},
],
),
start: SourcePosition {
line: 7,
col: 21,
},
end: SourcePosition {
line: 7,
col: 48,
},
},
},
start: SourcePosition {
line: 7,
col: 9,
},
end: SourcePosition {
line: 7,
col: 48,
},
},
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"emptyList",
),
start: SourcePosition {
line: 8,
col: 9,
},
end: SourcePosition {
line: 8,
col: 17,
},
},
value: Spanning {
item: List(
[],
),
start: SourcePosition {
line: 8,
col: 20,
},
end: SourcePosition {
line: 8,
col: 21,
},
},
},
start: SourcePosition {
line: 8,
col: 9,
},
end: SourcePosition {
line: 8,
col: 21,
},
},
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"emptyObject",
),
start: SourcePosition {
line: 9,
col: 9,
},
end: SourcePosition {
line: 9,
col: 19,
},
},
value: Spanning {
item: Object(
[],
),
start: SourcePosition {
line: 9,
col: 22,
},
end: SourcePosition {
line: 9,
col: 23,
},
},
},
start: SourcePosition {
line: 9,
col: 9,
},
end: SourcePosition {
line: 9,
col: 23,
},
},
],
start: SourcePosition {
line: 2,
col: 9,
},
end: SourcePosition {
line: 10,
col: 5,
},
},
),
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 8,
},
},
],
},
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 11,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 11,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,3 @@
query getOutput($input: Int = 5 $config: String = "Config") {
animal
}

View File

@ -0,0 +1,220 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: Some(
Spanning {
item: Name(
"getOutput",
),
start: SourcePosition {
line: 1,
col: 7,
},
end: SourcePosition {
line: 1,
col: 15,
},
},
),
variable_definitions: Some(
Spanning {
item: [
Spanning {
item: VariableDefinition {
name: Spanning {
item: Name(
"input",
),
start: SourcePosition {
line: 1,
col: 18,
},
end: SourcePosition {
line: 1,
col: 22,
},
},
var_type: Spanning {
item: TypeContainer {
base: Named(
TypeName(
Name(
"Int",
),
),
),
nullable: true,
},
start: SourcePosition {
line: 1,
col: 25,
},
end: SourcePosition {
line: 1,
col: 27,
},
},
default_value: Some(
Spanning {
item: SimpleValue(
Integer(
5,
),
),
start: SourcePosition {
line: 1,
col: 31,
},
end: SourcePosition {
line: 1,
col: 31,
},
},
),
},
start: SourcePosition {
line: 1,
col: 17,
},
end: SourcePosition {
line: 1,
col: 31,
},
},
Spanning {
item: VariableDefinition {
name: Spanning {
item: Name(
"config",
),
start: SourcePosition {
line: 1,
col: 34,
},
end: SourcePosition {
line: 1,
col: 39,
},
},
var_type: Spanning {
item: TypeContainer {
base: Named(
TypeName(
Name(
"String",
),
),
),
nullable: true,
},
start: SourcePosition {
line: 1,
col: 42,
},
end: SourcePosition {
line: 1,
col: 47,
},
},
default_value: Some(
Spanning {
item: SimpleValue(
String(
"Config",
),
),
start: SourcePosition {
line: 1,
col: 51,
},
end: SourcePosition {
line: 1,
col: 58,
},
},
),
},
start: SourcePosition {
line: 1,
col: 33,
},
end: SourcePosition {
line: 1,
col: 58,
},
},
],
start: SourcePosition {
line: 1,
col: 16,
},
end: SourcePosition {
line: 1,
col: 59,
},
},
),
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"animal",
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 10,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 10,
},
},
],
},
start: SourcePosition {
line: 1,
col: 61,
},
end: SourcePosition {
line: 3,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 3,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,8 @@
{
...friendFields
}
fragment friendFields on User {
id
name
}

View File

@ -0,0 +1,197 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: FragmentSpread(
FragmentSpread {
fragment_name: Spanning {
item: Name(
"friendFields",
),
start: SourcePosition {
line: 2,
col: 6,
},
end: SourcePosition {
line: 2,
col: 17,
},
},
directives: [],
},
),
start: SourcePosition {
line: 2,
col: 3,
},
end: SourcePosition {
line: 2,
col: 17,
},
},
],
},
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 3,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 3,
col: 1,
},
},
Spanning {
item: Fragment(
FragmentDefinition {
name: Spanning {
item: Name(
"friendFields",
),
start: SourcePosition {
line: 5,
col: 10,
},
end: SourcePosition {
line: 5,
col: 21,
},
},
type_condition: Spanning {
item: TypeCondition {
on: Spanning {
item: TypeName(
Name(
"User",
),
),
start: SourcePosition {
line: 5,
col: 26,
},
end: SourcePosition {
line: 5,
col: 29,
},
},
},
start: SourcePosition {
line: 5,
col: 23,
},
end: SourcePosition {
line: 5,
col: 29,
},
},
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"id",
),
start: SourcePosition {
line: 6,
col: 3,
},
end: SourcePosition {
line: 6,
col: 4,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 6,
col: 3,
},
end: SourcePosition {
line: 6,
col: 4,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"name",
),
start: SourcePosition {
line: 7,
col: 3,
},
end: SourcePosition {
line: 7,
col: 6,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 7,
col: 3,
},
end: SourcePosition {
line: 7,
col: 6,
},
},
],
},
start: SourcePosition {
line: 5,
col: 31,
},
end: SourcePosition {
line: 8,
col: 1,
},
},
},
),
start: SourcePosition {
line: 5,
col: 1,
},
end: SourcePosition {
line: 8,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,3 @@
query Foo($bar: Int) {
name
}

View File

@ -0,0 +1,142 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: Some(
Spanning {
item: Name(
"Foo",
),
start: SourcePosition {
line: 1,
col: 7,
},
end: SourcePosition {
line: 1,
col: 9,
},
},
),
variable_definitions: Some(
Spanning {
item: [
Spanning {
item: VariableDefinition {
name: Spanning {
item: Name(
"bar",
),
start: SourcePosition {
line: 1,
col: 12,
},
end: SourcePosition {
line: 1,
col: 14,
},
},
var_type: Spanning {
item: TypeContainer {
base: Named(
TypeName(
Name(
"Int",
),
),
),
nullable: true,
},
start: SourcePosition {
line: 1,
col: 17,
},
end: SourcePosition {
line: 1,
col: 19,
},
},
default_value: None,
},
start: SourcePosition {
line: 1,
col: 11,
},
end: SourcePosition {
line: 1,
col: 19,
},
},
],
start: SourcePosition {
line: 1,
col: 10,
},
end: SourcePosition {
line: 1,
col: 20,
},
},
),
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"name",
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 8,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 8,
},
},
],
},
start: SourcePosition {
line: 1,
col: 22,
},
end: SourcePosition {
line: 3,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 3,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,4 @@
query ($height: [Int]) {
id
trees(height: $height)
}

View File

@ -0,0 +1,217 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: None,
variable_definitions: Some(
Spanning {
item: [
Spanning {
item: VariableDefinition {
name: Spanning {
item: Name(
"height",
),
start: SourcePosition {
line: 1,
col: 9,
},
end: SourcePosition {
line: 1,
col: 14,
},
},
var_type: Spanning {
item: TypeContainer {
base: List(
TypeContainer {
base: Named(
TypeName(
Name(
"Int",
),
),
),
nullable: true,
},
),
nullable: true,
},
start: SourcePosition {
line: 1,
col: 17,
},
end: SourcePosition {
line: 1,
col: 21,
},
},
default_value: None,
},
start: SourcePosition {
line: 1,
col: 8,
},
end: SourcePosition {
line: 1,
col: 21,
},
},
],
start: SourcePosition {
line: 1,
col: 7,
},
end: SourcePosition {
line: 1,
col: 22,
},
},
),
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"id",
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 6,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 5,
},
end: SourcePosition {
line: 2,
col: 6,
},
},
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"trees",
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 9,
},
},
arguments: Some(
Spanning {
item: [
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"height",
),
start: SourcePosition {
line: 3,
col: 11,
},
end: SourcePosition {
line: 3,
col: 16,
},
},
value: Spanning {
item: Variable(
Name(
"height",
),
),
start: SourcePosition {
line: 3,
col: 19,
},
end: SourcePosition {
line: 3,
col: 25,
},
},
},
start: SourcePosition {
line: 3,
col: 11,
},
end: SourcePosition {
line: 3,
col: 25,
},
},
],
start: SourcePosition {
line: 3,
col: 10,
},
end: SourcePosition {
line: 3,
col: 26,
},
},
),
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 3,
col: 5,
},
end: SourcePosition {
line: 3,
col: 9,
},
},
],
},
start: SourcePosition {
line: 1,
col: 24,
},
end: SourcePosition {
line: 4,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 4,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,16 @@
query SomeQuery(
$param1: String!
$param2: String!
) {
item1(
param1: $param1
param2: $param2
) {
id
... on Fragment1 {
field3 {
field4
}
}
}
}

View File

@ -0,0 +1,462 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: Some(
Spanning {
item: Name(
"SomeQuery",
),
start: SourcePosition {
line: 1,
col: 7,
},
end: SourcePosition {
line: 1,
col: 15,
},
},
),
variable_definitions: Some(
Spanning {
item: [
Spanning {
item: VariableDefinition {
name: Spanning {
item: Name(
"param1",
),
start: SourcePosition {
line: 2,
col: 4,
},
end: SourcePosition {
line: 2,
col: 9,
},
},
var_type: Spanning {
item: TypeContainer {
base: Named(
TypeName(
Name(
"String",
),
),
),
nullable: false,
},
start: SourcePosition {
line: 2,
col: 12,
},
end: SourcePosition {
line: 2,
col: 18,
},
},
default_value: None,
},
start: SourcePosition {
line: 2,
col: 3,
},
end: SourcePosition {
line: 2,
col: 18,
},
},
Spanning {
item: VariableDefinition {
name: Spanning {
item: Name(
"param2",
),
start: SourcePosition {
line: 3,
col: 4,
},
end: SourcePosition {
line: 3,
col: 9,
},
},
var_type: Spanning {
item: TypeContainer {
base: Named(
TypeName(
Name(
"String",
),
),
),
nullable: false,
},
start: SourcePosition {
line: 3,
col: 12,
},
end: SourcePosition {
line: 3,
col: 18,
},
},
default_value: None,
},
start: SourcePosition {
line: 3,
col: 3,
},
end: SourcePosition {
line: 3,
col: 18,
},
},
],
start: SourcePosition {
line: 1,
col: 16,
},
end: SourcePosition {
line: 4,
col: 1,
},
},
),
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"item1",
),
start: SourcePosition {
line: 5,
col: 3,
},
end: SourcePosition {
line: 5,
col: 7,
},
},
arguments: Some(
Spanning {
item: [
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"param1",
),
start: SourcePosition {
line: 6,
col: 5,
},
end: SourcePosition {
line: 6,
col: 10,
},
},
value: Spanning {
item: Variable(
Name(
"param1",
),
),
start: SourcePosition {
line: 6,
col: 13,
},
end: SourcePosition {
line: 6,
col: 19,
},
},
},
start: SourcePosition {
line: 6,
col: 5,
},
end: SourcePosition {
line: 6,
col: 19,
},
},
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"param2",
),
start: SourcePosition {
line: 7,
col: 5,
},
end: SourcePosition {
line: 7,
col: 10,
},
},
value: Spanning {
item: Variable(
Name(
"param2",
),
),
start: SourcePosition {
line: 7,
col: 13,
},
end: SourcePosition {
line: 7,
col: 19,
},
},
},
start: SourcePosition {
line: 7,
col: 5,
},
end: SourcePosition {
line: 7,
col: 19,
},
},
],
start: SourcePosition {
line: 5,
col: 8,
},
end: SourcePosition {
line: 8,
col: 3,
},
},
),
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"id",
),
start: SourcePosition {
line: 9,
col: 5,
},
end: SourcePosition {
line: 9,
col: 6,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 9,
col: 5,
},
end: SourcePosition {
line: 9,
col: 6,
},
},
Spanning {
item: InlineFragment(
InlineFragment {
type_condition: Some(
Spanning {
item: TypeCondition {
on: Spanning {
item: TypeName(
Name(
"Fragment1",
),
),
start: SourcePosition {
line: 10,
col: 12,
},
end: SourcePosition {
line: 10,
col: 20,
},
},
},
start: SourcePosition {
line: 10,
col: 9,
},
end: SourcePosition {
line: 10,
col: 20,
},
},
),
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"field3",
),
start: SourcePosition {
line: 11,
col: 7,
},
end: SourcePosition {
line: 11,
col: 12,
},
},
arguments: None,
directives: [],
selection_set: Some(
Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"field4",
),
start: SourcePosition {
line: 12,
col: 9,
},
end: SourcePosition {
line: 12,
col: 14,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 12,
col: 9,
},
end: SourcePosition {
line: 12,
col: 14,
},
},
],
},
start: SourcePosition {
line: 11,
col: 14,
},
end: SourcePosition {
line: 13,
col: 7,
},
},
),
},
),
start: SourcePosition {
line: 11,
col: 7,
},
end: SourcePosition {
line: 11,
col: 12,
},
},
],
},
start: SourcePosition {
line: 10,
col: 22,
},
end: SourcePosition {
line: 14,
col: 5,
},
},
},
),
start: SourcePosition {
line: 10,
col: 5,
},
end: SourcePosition {
line: 14,
col: 5,
},
},
],
},
start: SourcePosition {
line: 8,
col: 5,
},
end: SourcePosition {
line: 15,
col: 3,
},
},
),
},
),
start: SourcePosition {
line: 5,
col: 3,
},
end: SourcePosition {
line: 5,
col: 7,
},
},
],
},
start: SourcePosition {
line: 4,
col: 3,
},
end: SourcePosition {
line: 16,
col: 1,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 16,
col: 1,
},
},
],
},
)

View File

@ -0,0 +1,4 @@
# Note @deprecated is only allowed in SDL AFAIU, but we'll allow it here
query getOutput($input: Int @deprecated $config: String = "Config" @tag(name: "team-customers")) {
animal
}

View File

@ -0,0 +1 @@
{ field(complex: { a: { b: [ $var ] } }) }

View File

@ -0,0 +1,214 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"field",
),
start: SourcePosition {
line: 1,
col: 3,
},
end: SourcePosition {
line: 1,
col: 7,
},
},
arguments: Some(
Spanning {
item: [
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"complex",
),
start: SourcePosition {
line: 1,
col: 9,
},
end: SourcePosition {
line: 1,
col: 15,
},
},
value: Spanning {
item: Object(
[
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"a",
),
start: SourcePosition {
line: 1,
col: 20,
},
end: SourcePosition {
line: 1,
col: 20,
},
},
value: Spanning {
item: Object(
[
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"b",
),
start: SourcePosition {
line: 1,
col: 25,
},
end: SourcePosition {
line: 1,
col: 25,
},
},
value: Spanning {
item: List(
[
Spanning {
item: Variable(
Name(
"var",
),
),
start: SourcePosition {
line: 1,
col: 30,
},
end: SourcePosition {
line: 1,
col: 33,
},
},
],
),
start: SourcePosition {
line: 1,
col: 28,
},
end: SourcePosition {
line: 1,
col: 35,
},
},
},
start: SourcePosition {
line: 1,
col: 25,
},
end: SourcePosition {
line: 1,
col: 35,
},
},
],
),
start: SourcePosition {
line: 1,
col: 23,
},
end: SourcePosition {
line: 1,
col: 37,
},
},
},
start: SourcePosition {
line: 1,
col: 20,
},
end: SourcePosition {
line: 1,
col: 37,
},
},
],
),
start: SourcePosition {
line: 1,
col: 18,
},
end: SourcePosition {
line: 1,
col: 39,
},
},
},
start: SourcePosition {
line: 1,
col: 9,
},
end: SourcePosition {
line: 1,
col: 39,
},
},
],
start: SourcePosition {
line: 1,
col: 8,
},
end: SourcePosition {
line: 1,
col: 40,
},
},
),
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 1,
col: 3,
},
end: SourcePosition {
line: 1,
col: 7,
},
},
],
},
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 1,
col: 42,
},
},
},
),
start: SourcePosition {
line: 1,
col: 1,
},
end: SourcePosition {
line: 1,
col: 42,
},
},
],
},
)

View File

@ -0,0 +1 @@
query Foo($x: Boolean = false @bar) { field }

View File

@ -0,0 +1,2 @@
# This comment has a \u0A0A multi-byte character.
{ field(arg: "Has a \u0A0A multi-byte character.") }

View File

@ -0,0 +1,122 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Query,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"field",
),
start: SourcePosition {
line: 2,
col: 3,
},
end: SourcePosition {
line: 2,
col: 7,
},
},
arguments: Some(
Spanning {
item: [
Spanning {
item: KeyValue {
key: Spanning {
item: Name(
"arg",
),
start: SourcePosition {
line: 2,
col: 9,
},
end: SourcePosition {
line: 2,
col: 11,
},
},
value: Spanning {
item: SimpleValue(
String(
"Has a ਊ multi-byte character.",
),
),
start: SourcePosition {
line: 2,
col: 14,
},
end: SourcePosition {
line: 2,
col: 49,
},
},
},
start: SourcePosition {
line: 2,
col: 9,
},
end: SourcePosition {
line: 2,
col: 49,
},
},
],
start: SourcePosition {
line: 2,
col: 8,
},
end: SourcePosition {
line: 2,
col: 50,
},
},
),
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 3,
},
end: SourcePosition {
line: 2,
col: 7,
},
},
],
},
start: SourcePosition {
line: 2,
col: 1,
},
end: SourcePosition {
line: 2,
col: 52,
},
},
},
),
start: SourcePosition {
line: 2,
col: 1,
},
end: SourcePosition {
line: 2,
col: 52,
},
},
],
},
)

View File

@ -0,0 +1,3 @@
mutation {
mutationField
}

View File

@ -0,0 +1,69 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Mutation,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"mutationField",
),
start: SourcePosition {
line: 2,
col: 9,
},
end: SourcePosition {
line: 2,
col: 21,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 9,
},
end: SourcePosition {
line: 2,
col: 21,
},
},
],
},
start: SourcePosition {
line: 1,
col: 16,
},
end: SourcePosition {
line: 3,
col: 7,
},
},
},
),
start: SourcePosition {
line: 1,
col: 7,
},
end: SourcePosition {
line: 3,
col: 7,
},
},
],
},
)

View File

@ -0,0 +1,3 @@
subscription {
subscriptionField
}

View File

@ -0,0 +1,69 @@
Ok(
ExecutableDocument {
items: [
Spanning {
item: Operation(
OperationDefinition {
ty: Subscription,
name: None,
variable_definitions: None,
directives: [],
selection_set: Spanning {
item: SelectionSet {
items: [
Spanning {
item: Field(
Field {
alias: None,
name: Spanning {
item: Name(
"subscriptionField",
),
start: SourcePosition {
line: 2,
col: 9,
},
end: SourcePosition {
line: 2,
col: 25,
},
},
arguments: None,
directives: [],
selection_set: None,
},
),
start: SourcePosition {
line: 2,
col: 9,
},
end: SourcePosition {
line: 2,
col: 25,
},
},
],
},
start: SourcePosition {
line: 1,
col: 20,
},
end: SourcePosition {
line: 3,
col: 7,
},
},
},
),
start: SourcePosition {
line: 1,
col: 7,
},
end: SourcePosition {
line: 3,
col: 7,
},
},
],
},
)

Some files were not shown because too many files have changed in this diff Show More