From 5f148aa29533e5ece27a07e3b751226674e94525 Mon Sep 17 00:00:00 2001 From: Graeme Coupar Date: Sun, 7 Jan 2024 16:34:02 +0000 Subject: [PATCH] parse `implements` on object --- cynic-parser/src/ast.rs | 1 + cynic-parser/src/ast/reader.rs | 8 ++++++++ cynic-parser/src/lexer/tokens.rs | 4 ++++ cynic-parser/src/lib.rs | 4 ++-- cynic-parser/src/printer.rs | 16 ++++++++++++++-- cynic-parser/src/schema.lalrpop | 21 ++++++++++++++++++++- 6 files changed, 49 insertions(+), 5 deletions(-) diff --git a/cynic-parser/src/ast.rs b/cynic-parser/src/ast.rs index 2505321c..6ef907bf 100644 --- a/cynic-parser/src/ast.rs +++ b/cynic-parser/src/ast.rs @@ -58,6 +58,7 @@ pub struct ObjectDefinition { pub name: StringId, pub fields: Vec, pub directives: Vec, + pub implements: Vec, } pub struct FieldDefinition { diff --git a/cynic-parser/src/ast/reader.rs b/cynic-parser/src/ast/reader.rs index 82663948..4d90efac 100644 --- a/cynic-parser/src/ast/reader.rs +++ b/cynic-parser/src/ast/reader.rs @@ -67,6 +67,14 @@ impl<'a> AstReader<'a, ObjectDefinitionId> { self.ast.lookup(self.ast.lookup(self.id).name) } + pub fn implements_interfaces(&self) -> impl Iterator + 'a { + self.ast + .lookup(self.id) + .implements + .iter() + .map(|id| self.ast.lookup(*id)) + } + pub fn fields(&self) -> impl Iterator> + 'a { self.ast .lookup(self.id) diff --git a/cynic-parser/src/lexer/tokens.rs b/cynic-parser/src/lexer/tokens.rs index 31602532..1c652501 100644 --- a/cynic-parser/src/lexer/tokens.rs +++ b/cynic-parser/src/lexer/tokens.rs @@ -98,6 +98,9 @@ pub enum Token<'a> { #[token("null")] Null, + #[token("implements")] + Implements, + // IntegerPart: -?(0|[1-9][0-9]*) // FractionalPart: \\.[0-9]+ // ExponentPart: [eE][+-]?[0-9]+ @@ -262,6 +265,7 @@ impl fmt::Display for Token<'_> { Token::True => "true", Token::False => "false", Token::Null => "null,", + Token::Implements => "implements", }; f.write_str(message) } diff --git a/cynic-parser/src/lib.rs b/cynic-parser/src/lib.rs index 545000f3..d04faf98 100644 --- a/cynic-parser/src/lib.rs +++ b/cynic-parser/src/lib.rs @@ -43,13 +43,13 @@ mod tests { fn test_basic_object() { insta::assert_snapshot!( parse_type_system_document(r#" - type MyType @hello { + type MyType implements Blah & Bloo @hello { field: Whatever @hello(name: ["string"]), other: [[Int!]]! }"# ).to_sdl(), @r###" - type MyType @hello { + type MyType implements Blah & Bloo @hello { field: Whatever@hello(name: ("string")) other: [[Int!]]! } diff --git a/cynic-parser/src/printer.rs b/cynic-parser/src/printer.rs index 927d16c9..ae7bab46 100644 --- a/cynic-parser/src/printer.rs +++ b/cynic-parser/src/printer.rs @@ -66,9 +66,21 @@ impl<'a> Pretty<'a, BoxAllocator> for NodeDisplay<'a, SchemaDefinitionId> { impl<'a> Pretty<'a, BoxAllocator> for NodeDisplay<'a, ObjectDefinitionId> { fn pretty(self, allocator: &'a BoxAllocator) -> pretty::DocBuilder<'a, BoxAllocator, ()> { - allocator + let mut builder = allocator .text(format!("type {}", self.0.name())) - .append(allocator.space()) + .append(allocator.space()); + + let interfaces = self.0.implements_interfaces().collect::>(); + + if !interfaces.is_empty() { + builder = builder + .append(allocator.text("implements")) + .append(allocator.space()) + .append(allocator.intersperse(interfaces, " & ")) + .append(allocator.space()); + } + + builder .append(allocator.intersperse(self.0.directives().map(NodeDisplay), allocator.line())) .append(allocator.space()) .append(allocator.text("{")) diff --git a/cynic-parser/src/schema.lalrpop b/cynic-parser/src/schema.lalrpop index 1840232a..7076f982 100644 --- a/cynic-parser/src/schema.lalrpop +++ b/cynic-parser/src/schema.lalrpop @@ -32,13 +32,29 @@ pub RootOperationTypeDefinition: RootOperationTypeDefinition = { } pub ObjectDefinition: ObjectDefinition = { - ty => ObjectDefinition { + ty => ObjectDefinition { name, directives, + implements: implements.unwrap_or_default(), fields: fields.unwrap_or_default () } }; +ImplementsInterfaces: Vec = { + "&" => { + let mut interfaces = interfaces; + interfaces.push(name); + interfaces + }, + implements "&"? => { + vec![name] + } +} + +ImplementItem: StringId = { + "&" => name, +} + FieldsDefinition: Vec = { "{" "}" => fields }; @@ -160,6 +176,7 @@ Ident: &'input str = { true => "true", false => "false", null => "null", + implements => "implements", } extern { @@ -183,6 +200,7 @@ extern { "!" => lexer::Token::Exclamation, "=" => lexer::Token::Equals, "@" => lexer::Token::At, + "&" => lexer::Token::Ampersand, RawIdent => lexer::Token::Identifier(<&'input str>), @@ -200,5 +218,6 @@ extern { true => lexer::Token::True, false => lexer::Token::False, null => lexer::Token::Null, + implements => lexer::Token::Implements, } } \ No newline at end of file