use crate::parser::grammar::description;
use crate::parser::grammar::directive;
use crate::parser::grammar::name;
use crate::parser::grammar::selection;
use crate::parser::grammar::ty;
use crate::parser::grammar::value::Constness;
use crate::parser::grammar::variable;
use crate::Parser;
use crate::SyntaxKind;
use crate::TokenKind;
use crate::S;
use crate::T;
pub(crate) fn fragment_definition(p: &mut Parser) {
let _g = p.start_node(SyntaxKind::FRAGMENT_DEFINITION);
if p.executable_descriptions_allowed() {
if let Some(TokenKind::StringValue) = p.peek() {
description::description(p);
}
}
p.bump(SyntaxKind::fragment_KW);
fragment_name(p);
if p.legacy_fragment_variables_allowed() {
if let Some(T!['(']) = p.peek() {
variable::variable_definitions(p);
}
}
type_condition(p);
if let Some(T![@]) = p.peek() {
directive::directives(p, Constness::NotConst);
}
match p.peek() {
Some(T!['{']) => selection::selection_set(p),
_ => p.err("expected a Selection Set"),
}
}
pub(crate) fn fragment_name(p: &mut Parser) {
let _g = p.start_node(SyntaxKind::FRAGMENT_NAME);
match p.peek_token() {
Some(token) if token.kind() == TokenKind::Name && token.data() == "on" => {
p.err("Fragment Name cannot be 'on'");
}
Some(token) if token.kind() == TokenKind::Name => {
name::name(p);
}
_ => p.err("expected Fragment Name"),
}
}
pub(crate) fn type_condition(p: &mut Parser) {
let _g = p.start_node(SyntaxKind::TYPE_CONDITION);
if let Some(token) = p.peek_token() {
if token.kind() == TokenKind::Name && token.data() == "on" {
p.bump(SyntaxKind::on_KW);
} else {
p.err("expected 'on'");
}
if let Some(TokenKind::Name) = p.peek() {
ty::named_type(p)
} else {
p.err("expected a Name in Type Condition")
}
} else {
p.err("expected Type Condition")
}
}
pub(crate) fn inline_fragment(p: &mut Parser) {
let _g = p.start_node(SyntaxKind::INLINE_FRAGMENT);
p.bump(S![...]);
if let Some(TokenKind::Name) = p.peek() {
type_condition(p);
}
if let Some(T![@]) = p.peek() {
directive::directives(p, Constness::NotConst);
}
match p.peek() {
Some(T!['{']) => selection::selection_set(p),
_ => p.err("expected Selection Set"),
}
}
pub(crate) fn fragment_spread(p: &mut Parser) {
let _g = p.start_node(SyntaxKind::FRAGMENT_SPREAD);
p.bump(S![...]);
match p.peek() {
Some(TokenKind::Name) => {
fragment_name(p);
}
_ => p.err("expected a Name"),
}
if let Some(T![@]) = p.peek() {
directive::directives(p, Constness::NotConst);
}
}
#[cfg(test)]
mod test {
use crate::cst;
use crate::Parser;
#[test]
fn it_parses_fragment_description_when_enabled() {
let input = "\"Fragment description\"\nfragment ProfilePic on User { id }";
let cst = Parser::new(input)
.allow_executable_descriptions(true)
.parse();
assert_eq!(cst.errors().len(), 0);
let def = cst.document().definitions().next().unwrap();
let cst::Definition::FragmentDefinition(frag) = def else {
panic!("expected a FragmentDefinition");
};
assert!(frag.description().is_some());
}
#[test]
fn it_parses_legacy_fragment_variables_when_enabled() {
let input = "fragment ProfilePic($size: Int = 32) on User { profilePic(size: $size) }";
let cst = Parser::new(input)
.allow_legacy_fragment_variables(true)
.parse();
assert_eq!(cst.errors().len(), 0);
let def = cst.document().definitions().next().unwrap();
let cst::Definition::FragmentDefinition(frag) = def else {
panic!("expected a FragmentDefinition");
};
assert!(frag.variable_definitions().is_some());
}
#[test]
fn it_errors_on_legacy_fragment_variables_when_disabled() {
let input = "fragment ProfilePic($size: Int) on User { id }";
let cst = Parser::new(input).parse();
assert_ne!(cst.errors().len(), 0);
}
}