diff --git a/bluejay-printer/src/argument.rs b/bluejay-printer/src/argument.rs deleted file mode 100644 index a82b19f5..00000000 --- a/bluejay-printer/src/argument.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::value::ValuePrinter; -use bluejay_core::{Argument, Arguments}; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct ArgumentPrinter<'a, const CONST: bool, T: Argument>(&'a T); - -impl<'a, const CONST: bool, T: Argument> ArgumentPrinter<'a, CONST, T> { - pub(crate) fn new(argument: &'a T) -> Self { - Self(argument) - } -} - -impl> Display for ArgumentPrinter<'_, CONST, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(argument) = *self; - write!( - f, - "{}: {}", - argument.name(), - ValuePrinter::new(argument.value()) - ) - } -} - -pub(crate) struct ArgumentsPrinter<'a, const CONST: bool, T: Arguments>(&'a T); - -impl<'a, const CONST: bool, T: Arguments> ArgumentsPrinter<'a, CONST, T> { - pub(crate) fn new(arguments: &'a T) -> Self { - Self(arguments) - } -} - -impl> Display for ArgumentsPrinter<'_, CONST, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(arguments) = *self; - if arguments.is_empty() { - return Ok(()); - } - write!(f, "(")?; - arguments - .iter() - .enumerate() - .try_for_each(|(idx, argument)| { - if idx != 0 { - write!(f, ", ")?; - } - write!(f, "{}", ArgumentPrinter::new(argument)) - })?; - write!(f, ")") - } -} - -#[cfg(test)] -mod tests { - use super::ArgumentsPrinter; - use bluejay_parser::ast::{Arguments, Parse}; - - #[test] - fn test_arguments() { - let s = "(a: 1, b: 2)"; - let parsed = Arguments::::parse(s).result.unwrap(); - assert_eq!(s, ArgumentsPrinter::new(&parsed).to_string()); - } -} diff --git a/bluejay-printer/src/definition.rs b/bluejay-printer/src/definition.rs deleted file mode 100644 index 50cbf3ed..00000000 --- a/bluejay-printer/src/definition.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod arguments_definition; -mod directive_definition; -mod enum_type_definition; -mod field_definition; -mod input_object_type_definition; -mod input_value_definition; -mod interface_implementations; -mod interface_type_definition; -mod object_type_definition; -mod scalar_type_definition; -mod schema_definition; -mod union_type_definition; - -pub use schema_definition::SchemaDefinitionPrinter; diff --git a/bluejay-printer/src/definition/arguments_definition.rs b/bluejay-printer/src/definition/arguments_definition.rs deleted file mode 100644 index c805c751..00000000 --- a/bluejay-printer/src/definition/arguments_definition.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::{ - definition::input_value_definition::InputValueDefinitionPrinter, write_indent, INDENTATION_SIZE, -}; -use bluejay_core::definition::ArgumentsDefinition; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct ArgumentsDefinitionPrinter<'a, T: ArgumentsDefinition> { - arguments_definition: &'a T, - indentation: usize, -} - -impl<'a, T: ArgumentsDefinition> ArgumentsDefinitionPrinter<'a, T> { - pub(crate) fn new(arguments_definition: &'a T, indentation: usize) -> Self { - Self { - arguments_definition, - indentation, - } - } -} - -impl Display for ArgumentsDefinitionPrinter<'_, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - arguments_definition, - indentation, - } = *self; - if arguments_definition.is_empty() { - return Ok(()); - } - - writeln!(f, "(")?; - - arguments_definition - .iter() - .enumerate() - .try_for_each(|(idx, ivd)| { - if idx != 0 { - writeln!(f)?; - } - write!( - f, - "{}", - InputValueDefinitionPrinter::new(ivd, indentation + INDENTATION_SIZE) - ) - })?; - - write_indent(f, indentation)?; - write!(f, ")") - } -} diff --git a/bluejay-printer/src/definition/directive_definition.rs b/bluejay-printer/src/definition/directive_definition.rs deleted file mode 100644 index 15ea866a..00000000 --- a/bluejay-printer/src/definition/directive_definition.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::{ - definition::arguments_definition::ArgumentsDefinitionPrinter, - string_value::BlockStringValuePrinter, -}; -use bluejay_core::{definition::DirectiveDefinition, AsIter}; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct DirectiveDefinitionPrinter<'a, D: DirectiveDefinition>(&'a D); - -impl<'a, D: DirectiveDefinition> DirectiveDefinitionPrinter<'a, D> { - pub(crate) fn new(directive_definition: &'a D) -> Self { - Self(directive_definition) - } -} - -impl Display for DirectiveDefinitionPrinter<'_, D> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(directive_definition) = *self; - if let Some(description) = directive_definition.description() { - write!(f, "{}", BlockStringValuePrinter::new(description, 0))?; - } - - write!(f, "directive @{}", directive_definition.name())?; - - if let Some(arguments_definition) = directive_definition.arguments_definition() { - write!( - f, - "{}", - ArgumentsDefinitionPrinter::new(arguments_definition, 0) - )?; - } - - if directive_definition.is_repeatable() { - write!(f, " repeatable")?; - } - - write!(f, " on ")?; - - directive_definition - .locations() - .iter() - .enumerate() - .try_for_each(|(idx, location)| { - if idx != 0 { - write!(f, " | ")?; - } - write!(f, "{location}") - })?; - - writeln!(f) - } -} diff --git a/bluejay-printer/src/definition/enum_type_definition.rs b/bluejay-printer/src/definition/enum_type_definition.rs deleted file mode 100644 index e558ca69..00000000 --- a/bluejay-printer/src/definition/enum_type_definition.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::{ - directive::DirectivesPrinter, string_value::BlockStringValuePrinter, write_indent, - INDENTATION_SIZE, -}; -use bluejay_core::{ - definition::{EnumTypeDefinition, EnumValueDefinition, HasDirectives}, - AsIter, -}; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct EnumTypeDefinitionPrinter<'a, E: EnumTypeDefinition>(&'a E); - -impl<'a, E: EnumTypeDefinition> EnumTypeDefinitionPrinter<'a, E> { - pub(crate) fn new(enum_type_definition: &'a E) -> Self { - Self(enum_type_definition) - } -} - -impl Display for EnumTypeDefinitionPrinter<'_, E> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(enum_type_definition) = *self; - if let Some(description) = enum_type_definition.description() { - write!(f, "{}", BlockStringValuePrinter::new(description, 0))?; - } - - write!(f, "enum {}", enum_type_definition.name())?; - - if let Some(directives) = enum_type_definition.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - writeln!(f, " {{")?; - - enum_type_definition - .enum_value_definitions() - .iter() - .enumerate() - .try_for_each(|(idx, evd)| { - if idx != 0 { - writeln!(f)?; - } - - if let Some(description) = evd.description() { - write!( - f, - "{}", - BlockStringValuePrinter::new(description, INDENTATION_SIZE) - )?; - } - - write_indent(f, INDENTATION_SIZE)?; - write!(f, "{}", evd.name())?; - - if let Some(directives) = evd.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - writeln!(f) - })?; - - writeln!(f, "}}") - } -} diff --git a/bluejay-printer/src/definition/field_definition.rs b/bluejay-printer/src/definition/field_definition.rs deleted file mode 100644 index 1c4e5161..00000000 --- a/bluejay-printer/src/definition/field_definition.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::{ - definition::arguments_definition::ArgumentsDefinitionPrinter, directive::DirectivesPrinter, - string_value::BlockStringValuePrinter, write_indent, INDENTATION_SIZE, -}; -use bluejay_core::definition::{FieldDefinition, FieldsDefinition, OutputType}; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct FieldDefinitionPrinter<'a, F: FieldDefinition> { - field_definition: &'a F, - indentation: usize, -} - -impl<'a, F: FieldDefinition> FieldDefinitionPrinter<'a, F> { - pub(crate) fn new(field_definition: &'a F, indentation: usize) -> Self { - Self { - field_definition, - indentation, - } - } -} - -impl Display for FieldDefinitionPrinter<'_, F> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - field_definition, - indentation, - } = *self; - if let Some(description) = field_definition.description() { - write!( - f, - "{}", - BlockStringValuePrinter::new(description, indentation) - )?; - } - - write_indent(f, indentation)?; - write!(f, "{}", field_definition.name(),)?; - - if let Some(arguments_definition) = field_definition.arguments_definition() { - write!( - f, - "{}", - ArgumentsDefinitionPrinter::new(arguments_definition, indentation) - )?; - } - - write!(f, ": {}", field_definition.r#type().display_name())?; - - if let Some(directives) = field_definition.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - writeln!(f) - } -} - -pub(crate) struct FieldsDefinitionPrinter<'a, F: FieldsDefinition> { - fields_definition: &'a F, - indentation: usize, -} - -impl<'a, F: FieldsDefinition> FieldsDefinitionPrinter<'a, F> { - pub(crate) fn new(fields_definition: &'a F, indentation: usize) -> Self { - Self { - fields_definition, - indentation, - } - } -} - -impl Display for FieldsDefinitionPrinter<'_, F> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - fields_definition, - indentation, - } = *self; - writeln!(f, "{{")?; - - fields_definition - .iter() - .filter(|fd| !fd.is_builtin()) - .enumerate() - .try_for_each(|(idx, fd)| { - if idx != 0 { - writeln!(f)?; - } - FieldDefinitionPrinter::new(fd, indentation + INDENTATION_SIZE).fmt(f) - })?; - - write_indent(f, indentation)?; - writeln!(f, "}}") - } -} diff --git a/bluejay-printer/src/definition/input_object_type_definition.rs b/bluejay-printer/src/definition/input_object_type_definition.rs deleted file mode 100644 index cf52df4a..00000000 --- a/bluejay-printer/src/definition/input_object_type_definition.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::{ - definition::input_value_definition::InputValueDefinitionPrinter, directive::DirectivesPrinter, - string_value::BlockStringValuePrinter, INDENTATION_SIZE, -}; -use bluejay_core::{definition::InputObjectTypeDefinition, AsIter}; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct InputObjectTypeDefinitionPrinter<'a, I: InputObjectTypeDefinition>(&'a I); - -impl<'a, I: InputObjectTypeDefinition> InputObjectTypeDefinitionPrinter<'a, I> { - pub(crate) fn new(input_object_type_definition: &'a I) -> Self { - Self(input_object_type_definition) - } -} - -impl Display for InputObjectTypeDefinitionPrinter<'_, I> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(input_object_type_definition) = *self; - if let Some(description) = input_object_type_definition.description() { - write!(f, "{}", BlockStringValuePrinter::new(description, 0))?; - } - - write!(f, "input {}", input_object_type_definition.name())?; - - if let Some(directives) = input_object_type_definition.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - writeln!(f, " {{")?; - - input_object_type_definition - .input_field_definitions() - .iter() - .enumerate() - .try_for_each(|(idx, ivd)| { - if idx != 0 { - writeln!(f)?; - } - write!( - f, - "{}", - InputValueDefinitionPrinter::new(ivd, INDENTATION_SIZE) - ) - })?; - - writeln!(f, "}}") - } -} diff --git a/bluejay-printer/src/definition/input_value_definition.rs b/bluejay-printer/src/definition/input_value_definition.rs deleted file mode 100644 index a9793b0f..00000000 --- a/bluejay-printer/src/definition/input_value_definition.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::{ - directive::DirectivesPrinter, string_value::BlockStringValuePrinter, value::ValuePrinter, - write_indent, -}; -use bluejay_core::definition::{InputType, InputValueDefinition}; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct InputValueDefinitionPrinter<'a, T: InputValueDefinition> { - input_value_definition: &'a T, - indentation: usize, -} - -impl<'a, T: InputValueDefinition> InputValueDefinitionPrinter<'a, T> { - pub(crate) fn new(input_value_definition: &'a T, indentation: usize) -> Self { - Self { - input_value_definition, - indentation, - } - } -} - -impl Display for InputValueDefinitionPrinter<'_, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - input_value_definition, - indentation, - } = *self; - if let Some(description) = input_value_definition.description() { - write!( - f, - "{}", - BlockStringValuePrinter::new(description, indentation) - )?; - } - - write_indent(f, indentation)?; - write!( - f, - "{}: {}", - input_value_definition.name(), - input_value_definition.r#type().display_name(), - )?; - - if let Some(default_value) = input_value_definition.default_value() { - write!(f, " = {}", ValuePrinter::new(default_value))?; - } - - if let Some(directives) = input_value_definition.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - writeln!(f) - } -} diff --git a/bluejay-printer/src/definition/interface_implementations.rs b/bluejay-printer/src/definition/interface_implementations.rs deleted file mode 100644 index d644e912..00000000 --- a/bluejay-printer/src/definition/interface_implementations.rs +++ /dev/null @@ -1,30 +0,0 @@ -use bluejay_core::definition::{InterfaceImplementation, InterfaceImplementations}; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct InterfaceImplementationsPrinter<'a, I: InterfaceImplementations>(&'a I); - -impl<'a, I: InterfaceImplementations> InterfaceImplementationsPrinter<'a, I> { - pub(crate) fn new(interface_implementations: &'a I) -> Self { - Self(interface_implementations) - } -} - -impl Display for InterfaceImplementationsPrinter<'_, I> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(interface_implementations) = *self; - if !interface_implementations.is_empty() { - write!(f, " implements ")?; - interface_implementations - .iter() - .enumerate() - .try_for_each(|(idx, ii)| { - if idx != 0 { - write!(f, " & ")?; - } - write!(f, "{}", ii.name()) - }) - } else { - Ok(()) - } - } -} diff --git a/bluejay-printer/src/definition/interface_type_definition.rs b/bluejay-printer/src/definition/interface_type_definition.rs deleted file mode 100644 index e3d30684..00000000 --- a/bluejay-printer/src/definition/interface_type_definition.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::{ - definition::{ - field_definition::FieldsDefinitionPrinter, - interface_implementations::InterfaceImplementationsPrinter, - }, - directive::DirectivesPrinter, - string_value::BlockStringValuePrinter, -}; -use bluejay_core::definition::InterfaceTypeDefinition; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct InterfaceTypeDefinitionPrinter<'a, I: InterfaceTypeDefinition>(&'a I); - -impl<'a, I: InterfaceTypeDefinition> InterfaceTypeDefinitionPrinter<'a, I> { - pub(crate) fn new(interface_type_definition: &'a I) -> Self { - Self(interface_type_definition) - } -} - -impl Display for InterfaceTypeDefinitionPrinter<'_, I> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(interface_type_definition) = *self; - if let Some(description) = interface_type_definition.description() { - write!(f, "{}", BlockStringValuePrinter::new(description, 0))?; - } - - write!(f, "interface {}", interface_type_definition.name())?; - - if let Some(interface_implementations) = - interface_type_definition.interface_implementations() - { - write!( - f, - "{}", - InterfaceImplementationsPrinter::new(interface_implementations) - )?; - } - - if let Some(directives) = interface_type_definition.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - write!( - f, - " {}", - FieldsDefinitionPrinter::new(interface_type_definition.fields_definition(), 0) - ) - } -} diff --git a/bluejay-printer/src/definition/object_type_definition.rs b/bluejay-printer/src/definition/object_type_definition.rs deleted file mode 100644 index 4544bd80..00000000 --- a/bluejay-printer/src/definition/object_type_definition.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::{ - definition::{ - field_definition::FieldsDefinitionPrinter, - interface_implementations::InterfaceImplementationsPrinter, - }, - directive::DirectivesPrinter, - string_value::BlockStringValuePrinter, -}; -use bluejay_core::definition::ObjectTypeDefinition; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct ObjectTypeDefinitionPrinter<'a, O: ObjectTypeDefinition>(&'a O); - -impl<'a, O: ObjectTypeDefinition> ObjectTypeDefinitionPrinter<'a, O> { - pub(crate) fn new(object_type_definition: &'a O) -> Self { - Self(object_type_definition) - } -} - -impl Display for ObjectTypeDefinitionPrinter<'_, O> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(object_type_definition) = *self; - if let Some(description) = object_type_definition.description() { - write!(f, "{}", BlockStringValuePrinter::new(description, 0))?; - } - - write!(f, "type {}", object_type_definition.name())?; - - if let Some(interface_implementations) = object_type_definition.interface_implementations() - { - write!( - f, - "{}", - InterfaceImplementationsPrinter::new(interface_implementations) - )?; - } - - if let Some(directives) = object_type_definition.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - write!( - f, - " {}", - FieldsDefinitionPrinter::new(object_type_definition.fields_definition(), 0) - ) - } -} diff --git a/bluejay-printer/src/definition/scalar_type_definition.rs b/bluejay-printer/src/definition/scalar_type_definition.rs deleted file mode 100644 index 31dfbe21..00000000 --- a/bluejay-printer/src/definition/scalar_type_definition.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::{directive::DirectivesPrinter, string_value::BlockStringValuePrinter}; -use bluejay_core::definition::ScalarTypeDefinition; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct ScalarTypeDefinitionPrinter<'a, S: ScalarTypeDefinition>(&'a S); - -impl<'a, S: ScalarTypeDefinition> ScalarTypeDefinitionPrinter<'a, S> { - pub(crate) fn new(scalar_type_definition: &'a S) -> Self { - Self(scalar_type_definition) - } -} - -impl Display for ScalarTypeDefinitionPrinter<'_, S> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(scalar_type_definition) = *self; - if let Some(description) = scalar_type_definition.description() { - write!(f, "{}", BlockStringValuePrinter::new(description, 0))?; - } - - write!(f, "scalar {}", scalar_type_definition.name())?; - - if let Some(directives) = scalar_type_definition.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - writeln!(f) - } -} diff --git a/bluejay-printer/src/definition/schema_definition.rs b/bluejay-printer/src/definition/schema_definition.rs deleted file mode 100644 index b2c95620..00000000 --- a/bluejay-printer/src/definition/schema_definition.rs +++ /dev/null @@ -1,160 +0,0 @@ -use crate::{ - definition::{ - directive_definition::DirectiveDefinitionPrinter, - enum_type_definition::EnumTypeDefinitionPrinter, - input_object_type_definition::InputObjectTypeDefinitionPrinter, - interface_type_definition::InterfaceTypeDefinitionPrinter, - object_type_definition::ObjectTypeDefinitionPrinter, - scalar_type_definition::ScalarTypeDefinitionPrinter, - union_type_definition::UnionTypeDefinitionPrinter, - }, - directive::DirectivesPrinter, - string_value::BlockStringValuePrinter, -}; -use bluejay_core::{ - definition::{ - DirectiveDefinition, ObjectTypeDefinition, SchemaDefinition, TypeDefinitionReference, - }, - AsIter, -}; -use std::fmt::{Display, Formatter, Result}; - -pub struct SchemaDefinitionPrinter<'a, S: SchemaDefinition>(&'a S); - -impl<'a, S: SchemaDefinition> SchemaDefinitionPrinter<'a, S> { - pub fn new(schema_definition: &'a S) -> Self { - Self(schema_definition) - } - - pub fn to_string(schema_definition: &'a S) -> String { - Self::new(schema_definition).to_string() - } - - fn is_implicit(schema_definition: &S) -> bool { - schema_definition.description().is_none() - && schema_definition.query().name() == "Query" - && schema_definition - .mutation() - .map(|mutation| mutation.name() == "Mutation") - .unwrap_or(true) - && schema_definition - .subscription() - .map(|subscription| subscription.name() == "Subscription") - .unwrap_or(true) - && schema_definition - .directives() - .map(AsIter::is_empty) - .unwrap_or(true) - } - - fn fmt_explicit_schema_definition(schema_definition: &S, f: &mut Formatter<'_>) -> Result { - if let Some(description) = schema_definition.description() { - write!(f, "{}", BlockStringValuePrinter::new(description, 0))?; - } - - write!(f, "schema")?; - - if let Some(directives) = schema_definition.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - writeln!(f, " {{\n query: {}", schema_definition.query().name())?; - - if let Some(mutation) = schema_definition.mutation() { - writeln!(f, " mutation: {}", mutation.name())?; - } - - if let Some(subscription) = schema_definition.subscription() { - writeln!(f, " subscription: {}", subscription.name())?; - } - - writeln!(f, "}}") - } -} - -impl Display for SchemaDefinitionPrinter<'_, S> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(schema_definition) = *self; - schema_definition - .directive_definitions() - .filter(|dd| !dd.is_builtin()) - .enumerate() - .try_for_each(|(idx, dd)| { - if idx != 0 { - writeln!(f)?; - } - write!(f, "{}", DirectiveDefinitionPrinter::new(dd)) - })?; - - let had_directives_to_output = schema_definition - .directive_definitions() - .any(|dd| !dd.is_builtin()); - - schema_definition - .type_definitions() - .filter(|tdr| !tdr.is_builtin()) - .enumerate() - .try_for_each(|(idx, tdr)| { - if had_directives_to_output || idx != 0 { - writeln!(f)?; - } - match tdr { - TypeDefinitionReference::BuiltinScalar(_) => Ok(()), - TypeDefinitionReference::CustomScalar(cstd) => { - write!(f, "{}", ScalarTypeDefinitionPrinter::new(cstd)) - } - TypeDefinitionReference::Enum(etd) => { - write!(f, "{}", EnumTypeDefinitionPrinter::new(etd)) - } - TypeDefinitionReference::InputObject(iotd) => { - write!(f, "{}", InputObjectTypeDefinitionPrinter::new(iotd)) - } - TypeDefinitionReference::Interface(itd) => { - write!(f, "{}", InterfaceTypeDefinitionPrinter::new(itd)) - } - TypeDefinitionReference::Object(otd) => { - write!(f, "{}", ObjectTypeDefinitionPrinter::new(otd)) - } - TypeDefinitionReference::Union(utd) => { - write!(f, "{}", UnionTypeDefinitionPrinter::new(utd)) - } - } - })?; - - if Self::is_implicit(schema_definition) { - Ok(()) - } else { - if had_directives_to_output - || schema_definition - .type_definitions() - .any(|td| !td.is_builtin()) - { - writeln!(f)?; - } - Self::fmt_explicit_schema_definition(schema_definition, f) - } - } -} - -#[cfg(test)] -mod tests { - use super::SchemaDefinitionPrinter; - use bluejay_parser::ast::{ - definition::{DefinitionDocument, SchemaDefinition}, - Parse, - }; - - #[test] - fn test_schema_dump() { - insta::glob!("test_data/schema_definition/*.graphql", |path| { - let input = std::fs::read_to_string(path).unwrap(); - let document: DefinitionDocument = - DefinitionDocument::parse(input.as_str()).result.unwrap(); - let schema_definition = SchemaDefinition::try_from(&document).unwrap(); - similar_asserts::assert_eq!( - input, - SchemaDefinitionPrinter(&schema_definition).to_string() - ); - }); - } -} diff --git a/bluejay-printer/src/definition/test_data/schema_definition/explicit_schema.graphql b/bluejay-printer/src/definition/test_data/schema_definition/explicit_schema.graphql index c08aa5af..e6586775 100644 --- a/bluejay-printer/src/definition/test_data/schema_definition/explicit_schema.graphql +++ b/bluejay-printer/src/definition/test_data/schema_definition/explicit_schema.graphql @@ -10,5 +10,6 @@ type MyQueryRootType { schema { query: MyQueryRootType + mutation: MyMutationRootType } diff --git a/bluejay-printer/src/definition/union_type_definition.rs b/bluejay-printer/src/definition/union_type_definition.rs deleted file mode 100644 index ba982c62..00000000 --- a/bluejay-printer/src/definition/union_type_definition.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::{directive::DirectivesPrinter, string_value::BlockStringValuePrinter}; -use bluejay_core::{ - definition::{UnionMemberType, UnionTypeDefinition}, - AsIter, -}; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct UnionTypeDefinitionPrinter<'a, U: UnionTypeDefinition>(&'a U); - -impl<'a, U: UnionTypeDefinition> UnionTypeDefinitionPrinter<'a, U> { - pub(crate) fn new(union_type_definition: &'a U) -> Self { - Self(union_type_definition) - } -} - -impl Display for UnionTypeDefinitionPrinter<'_, U> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(union_type_definition) = *self; - if let Some(description) = union_type_definition.description() { - write!(f, "{}", BlockStringValuePrinter::new(description, 0))?; - } - - write!(f, "union {}", union_type_definition.name())?; - - if let Some(directives) = union_type_definition.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - write!(f, " = ")?; - - union_type_definition - .union_member_types() - .iter() - .enumerate() - .try_for_each(|(idx, union_member)| { - if idx != 0 { - write!(f, " | ")?; - } - write!(f, "{}", union_member.name()) - })?; - - writeln!(f) - } -} diff --git a/bluejay-printer/src/directive.rs b/bluejay-printer/src/directive.rs deleted file mode 100644 index 527f3d80..00000000 --- a/bluejay-printer/src/directive.rs +++ /dev/null @@ -1,52 +0,0 @@ -use crate::argument::ArgumentsPrinter; -use bluejay_core::{Directive, Directives}; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct DirectivePrinter<'a, const CONST: bool, T: Directive>(&'a T); - -impl<'a, const CONST: bool, T: Directive> DirectivePrinter<'a, CONST, T> { - pub(crate) fn new(directive: &'a T) -> Self { - Self(directive) - } -} - -impl> Display for DirectivePrinter<'_, CONST, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(directive) = *self; - write!(f, "@{}", directive.name())?; - if let Some(arguments) = directive.arguments() { - write!(f, "{}", ArgumentsPrinter::new(arguments))?; - } - Ok(()) - } -} - -pub(crate) struct DirectivesPrinter<'a, const CONST: bool, T: Directives>(&'a T); - -impl<'a, const CONST: bool, T: Directives> DirectivesPrinter<'a, CONST, T> { - pub(crate) fn new(directives: &'a T) -> Self { - Self(directives) - } -} - -impl> Display for DirectivesPrinter<'_, CONST, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(directives) = *self; - directives - .iter() - .try_for_each(|directive| write!(f, " {}", DirectivePrinter::new(directive))) - } -} - -#[cfg(test)] -mod tests { - use super::DirectivesPrinter; - use bluejay_parser::ast::{Directives, Parse}; - - #[test] - fn test_directives() { - let s = " @foo(a: 1, b: 2) @bar"; - let parsed = Directives::::parse(s).result.unwrap(); - assert_eq!(s, DirectivesPrinter::new(&parsed).to_string()); - } -} diff --git a/bluejay-printer/src/executable.rs b/bluejay-printer/src/executable.rs deleted file mode 100644 index 836d83c5..00000000 --- a/bluejay-printer/src/executable.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod executable_document; -mod field; -mod fragment_definition; -mod fragment_spread; -mod inline_fragment; -mod operation_definition; -mod selection; -mod selection_set; -mod variable_definition; - -pub use executable_document::ExecutableDocumentPrinter; -use field::FieldPrinter; -use fragment_definition::FragmentDefinitionPrinter; -use fragment_spread::FragmentSpreadPrinter; -use inline_fragment::InlineFragmentPrinter; -use operation_definition::OperationDefinitionPrinter; -use selection::SelectionPrinter; -use selection_set::SelectionSetPrinter; -use variable_definition::VariableDefinitionsPrinter; diff --git a/bluejay-printer/src/executable/executable_document.rs b/bluejay-printer/src/executable/executable_document.rs deleted file mode 100644 index 25363808..00000000 --- a/bluejay-printer/src/executable/executable_document.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::executable::{FragmentDefinitionPrinter, OperationDefinitionPrinter}; -use bluejay_core::executable::ExecutableDocument; -use std::fmt::{Display, Formatter, Result}; - -pub struct ExecutableDocumentPrinter<'a, T: ExecutableDocument> { - executable_document: &'a T, -} - -impl<'a, T: ExecutableDocument> ExecutableDocumentPrinter<'a, T> { - pub fn new(executable_document: &'a T) -> Self { - Self { - executable_document, - } - } - - pub fn to_string(executable_document: &'a T) -> String { - Self::new(executable_document).to_string() - } -} - -impl Display for ExecutableDocumentPrinter<'_, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - executable_document, - } = *self; - executable_document - .operation_definitions() - .enumerate() - .try_for_each(|(idx, operation_definition)| { - if idx != 0 { - writeln!(f)?; - } - writeln!( - f, - "{}", - OperationDefinitionPrinter::new(operation_definition) - ) - })?; - - executable_document - .fragment_definitions() - .try_for_each(|fragment_definition| { - writeln!(f)?; - writeln!(f, "{}", FragmentDefinitionPrinter::new(fragment_definition)) - }) - } -} diff --git a/bluejay-printer/src/executable/field.rs b/bluejay-printer/src/executable/field.rs deleted file mode 100644 index 90473135..00000000 --- a/bluejay-printer/src/executable/field.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::{ - argument::ArgumentsPrinter, directive::DirectivesPrinter, executable::SelectionSetPrinter, - write_indent, -}; -use bluejay_core::executable::Field; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct FieldPrinter<'a, F: Field> { - field: &'a F, - indentation: usize, -} - -impl<'a, F: Field> FieldPrinter<'a, F> { - pub(crate) fn new(field: &'a F, indentation: usize) -> Self { - Self { field, indentation } - } -} - -impl Display for FieldPrinter<'_, F> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { field, indentation } = *self; - write_indent(f, indentation)?; - if let Some(alias) = field.alias() { - write!(f, "{}: ", alias)?; - } - write!(f, "{}", field.name())?; - if let Some(arguments) = field.arguments() { - write!(f, "{}", ArgumentsPrinter::new(arguments))?; - } - if let Some(directives) = field.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - if let Some(selection_set) = field.selection_set() { - write!( - f, - " {}", - SelectionSetPrinter::new(selection_set, indentation) - )?; - } - Ok(()) - } -} diff --git a/bluejay-printer/src/executable/fragment_definition.rs b/bluejay-printer/src/executable/fragment_definition.rs deleted file mode 100644 index fd3ffa0d..00000000 --- a/bluejay-printer/src/executable/fragment_definition.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::executable::SelectionSetPrinter; -use bluejay_core::executable::FragmentDefinition; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct FragmentDefinitionPrinter<'a, T: FragmentDefinition> { - fragment_definition: &'a T, -} - -impl<'a, T: FragmentDefinition> FragmentDefinitionPrinter<'a, T> { - pub(crate) fn new(fragment_definition: &'a T) -> Self { - Self { - fragment_definition, - } - } -} - -impl Display for FragmentDefinitionPrinter<'_, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - fragment_definition, - } = *self; - write!( - f, - "fragment {} on {} {}", - fragment_definition.name(), - fragment_definition.type_condition(), - SelectionSetPrinter::new(fragment_definition.selection_set(), 0), - ) - } -} diff --git a/bluejay-printer/src/executable/fragment_spread.rs b/bluejay-printer/src/executable/fragment_spread.rs deleted file mode 100644 index ae2daccd..00000000 --- a/bluejay-printer/src/executable/fragment_spread.rs +++ /dev/null @@ -1,33 +0,0 @@ -use bluejay_core::executable::FragmentSpread; -use std::fmt::{Display, Formatter, Result}; - -use crate::{directive::DirectivesPrinter, write_indent}; - -pub(crate) struct FragmentSpreadPrinter<'a, T: FragmentSpread> { - fragment_spread: &'a T, - indentation: usize, -} - -impl<'a, T: FragmentSpread> FragmentSpreadPrinter<'a, T> { - pub(crate) fn new(fragment_spread: &'a T, indentation: usize) -> Self { - Self { - fragment_spread, - indentation, - } - } -} - -impl Display for FragmentSpreadPrinter<'_, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - fragment_spread, - indentation, - } = *self; - write_indent(f, indentation)?; - write!(f, "...{}", fragment_spread.name())?; - if let Some(directives) = fragment_spread.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - }; - Ok(()) - } -} diff --git a/bluejay-printer/src/executable/inline_fragment.rs b/bluejay-printer/src/executable/inline_fragment.rs deleted file mode 100644 index f07d514e..00000000 --- a/bluejay-printer/src/executable/inline_fragment.rs +++ /dev/null @@ -1,40 +0,0 @@ -use crate::{directive::DirectivesPrinter, executable::SelectionSetPrinter, write_indent}; -use bluejay_core::executable::InlineFragment; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct InlineFragmentPrinter<'a, I: InlineFragment> { - inline_fragment: &'a I, - indentation: usize, -} - -impl<'a, I: InlineFragment> InlineFragmentPrinter<'a, I> { - pub(crate) fn new(inline_fragment: &'a I, indentation: usize) -> Self { - Self { - inline_fragment, - indentation, - } - } -} - -impl Display for InlineFragmentPrinter<'_, I> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - inline_fragment, - indentation, - } = *self; - write_indent(f, indentation)?; - write!(f, "...")?; - if let Some(type_condition) = inline_fragment.type_condition() { - write!(f, " on {}", type_condition)?; - } - if let Some(directives) = inline_fragment.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - - write!( - f, - " {}", - SelectionSetPrinter::new(inline_fragment.selection_set(), indentation) - ) - } -} diff --git a/bluejay-printer/src/executable/operation_definition.rs b/bluejay-printer/src/executable/operation_definition.rs deleted file mode 100644 index a9169033..00000000 --- a/bluejay-printer/src/executable/operation_definition.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::{ - directive::DirectivesPrinter, - executable::{SelectionSetPrinter, VariableDefinitionsPrinter}, -}; -use bluejay_core::executable::OperationDefinition; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct OperationDefinitionPrinter<'a, O: OperationDefinition> { - operation_definition: &'a O, -} - -impl<'a, O: OperationDefinition> OperationDefinitionPrinter<'a, O> { - pub(crate) fn new(operation_definition: &'a O) -> Self { - Self { - operation_definition, - } - } -} - -impl Display for OperationDefinitionPrinter<'_, O> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - operation_definition, - } = *self; - let operation_definition_reference = operation_definition.as_ref(); - write!(f, "{}", operation_definition_reference.operation_type())?; - if let Some(name) = operation_definition_reference.name() { - write!(f, " {}", name)?; - } - if let Some(variable_definitions) = operation_definition_reference.variable_definitions() { - write!( - f, - "{}", - VariableDefinitionsPrinter::new(variable_definitions) - )?; - } - if let Some(directives) = operation_definition_reference.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - } - write!( - f, - " {}", - SelectionSetPrinter::new(operation_definition_reference.selection_set(), 0) - ) - } -} diff --git a/bluejay-printer/src/executable/selection.rs b/bluejay-printer/src/executable/selection.rs deleted file mode 100644 index 4a63f580..00000000 --- a/bluejay-printer/src/executable/selection.rs +++ /dev/null @@ -1,43 +0,0 @@ -use crate::executable::{FieldPrinter, FragmentSpreadPrinter, InlineFragmentPrinter}; -use bluejay_core::executable::{Selection, SelectionReference}; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct SelectionPrinter<'a, S: Selection> { - selection: &'a S, - indentation: usize, -} - -impl<'a, S: Selection> SelectionPrinter<'a, S> { - pub(crate) fn new(selection: &'a S, indentation: usize) -> Self { - Self { - selection, - indentation, - } - } -} - -impl Display for SelectionPrinter<'_, S> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - selection, - indentation, - } = *self; - match selection.as_ref() { - SelectionReference::Field(field) => { - write!(f, "{}", FieldPrinter::new(field, indentation)) - } - SelectionReference::FragmentSpread(fragment_spread) => { - write!( - f, - "{}", - FragmentSpreadPrinter::new(fragment_spread, indentation) - ) - } - SelectionReference::InlineFragment(inline_fragment) => write!( - f, - "{}", - InlineFragmentPrinter::new(inline_fragment, indentation) - ), - } - } -} diff --git a/bluejay-printer/src/executable/selection_set.rs b/bluejay-printer/src/executable/selection_set.rs deleted file mode 100644 index 6e489113..00000000 --- a/bluejay-printer/src/executable/selection_set.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::{executable::SelectionPrinter, write_indent, INDENTATION_SIZE}; -use bluejay_core::executable::SelectionSet; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct SelectionSetPrinter<'a, S: SelectionSet> { - selection_set: &'a S, - indentation: usize, -} - -impl<'a, S: SelectionSet> SelectionSetPrinter<'a, S> { - pub(crate) fn new(selection_set: &'a S, indentation: usize) -> Self { - Self { - selection_set, - indentation, - } - } -} - -impl Display for SelectionSetPrinter<'_, S> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - selection_set, - indentation, - } = *self; - writeln!(f, "{{")?; - selection_set.iter().try_for_each(|selection| { - writeln!( - f, - "{}", - SelectionPrinter::new(selection, indentation + INDENTATION_SIZE) - ) - })?; - write_indent(f, indentation)?; - write!(f, "}}") - } -} diff --git a/bluejay-printer/src/executable/variable_definition.rs b/bluejay-printer/src/executable/variable_definition.rs deleted file mode 100644 index 7cd3686a..00000000 --- a/bluejay-printer/src/executable/variable_definition.rs +++ /dev/null @@ -1,71 +0,0 @@ -use crate::{directive::DirectivesPrinter, value::ValuePrinter}; -use bluejay_core::executable::{VariableDefinition, VariableDefinitions, VariableType}; - -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct VariableDefinitionPrinter<'a, T: VariableDefinition> { - variable_definition: &'a T, -} - -impl<'a, T: VariableDefinition> VariableDefinitionPrinter<'a, T> { - pub(crate) fn new(variable_definition: &'a T) -> Self { - Self { - variable_definition, - } - } -} - -impl Display for VariableDefinitionPrinter<'_, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - variable_definition, - } = *self; - write!( - f, - "${}: {}", - variable_definition.variable(), - variable_definition.r#type().as_ref().display_name(), - )?; - if let Some(default_value) = variable_definition.default_value() { - write!(f, " = {}", ValuePrinter::new(default_value))?; - } - - if let Some(directives) = variable_definition.directives() { - write!(f, "{}", DirectivesPrinter::new(directives))?; - }; - Ok(()) - } -} - -pub(crate) struct VariableDefinitionsPrinter<'a, T: VariableDefinitions> { - variable_definitions: &'a T, -} - -impl<'a, T: VariableDefinitions> VariableDefinitionsPrinter<'a, T> { - pub(crate) fn new(variable_definitions: &'a T) -> Self { - Self { - variable_definitions, - } - } -} - -impl Display for VariableDefinitionsPrinter<'_, T> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { - variable_definitions, - } = *self; - if !variable_definitions.is_empty() { - write!(f, "(")?; - variable_definitions.iter().enumerate().try_for_each( - |(idx, variable_definition)| { - if idx != 0 { - write!(f, ", ")?; - } - write!(f, "{}", VariableDefinitionPrinter::new(variable_definition)) - }, - )?; - write!(f, ")")?; - } - Ok(()) - } -} diff --git a/bluejay-printer/src/format.rs b/bluejay-printer/src/format.rs new file mode 100644 index 00000000..ffff7f88 --- /dev/null +++ b/bluejay-printer/src/format.rs @@ -0,0 +1,242 @@ +use std::fmt; + +/// Escapes triple-quote sequences in a block string by replacing `"""` with `\"""`. +pub fn escape_block_string(s: &str) -> String { + s.replace("\"\"\"", "\\\"\"\"") +} + +/// Controls the whitespace and formatting style used by [`crate::Serializer`] when +/// writing GraphQL output. +/// +/// Implement this trait to define custom formatting strategies beyond the +/// provided [`PrettyFormatter`] and [`CompactFormatter`]. +/// +/// The `&mut self` receiver on every method allows formatters to maintain state +/// (e.g. tracking the current column for line-wrapping heuristics). +/// +/// All `depth` parameters represent a logical nesting level (0 = top-level, +/// 1 = one level in, etc.). The formatter decides how to render that +/// (e.g. multiply by an indent width, or ignore it entirely). +pub trait Formatter { + /// Writes indentation for the given nesting `depth`. + /// Called before block members, field definitions, enum values, and + /// similar indented constructs. + fn write_indent(&mut self, w: &mut W, depth: usize) -> fmt::Result; + + /// Opens a brace-delimited block (`{`). Called at the start of selection + /// sets, field definition lists, enum bodies, and similar constructs. + /// `depth` is the nesting level of the block being opened. + fn begin_block(&mut self, w: &mut W, depth: usize) -> fmt::Result; + + /// Closes a brace-delimited block (`}`). `depth` is the nesting level + /// of the block being closed (i.e. the same depth that was current when + /// [`begin_block`](Formatter::begin_block) was called). + fn end_block(&mut self, w: &mut W, depth: usize) -> fmt::Result; + + /// Terminates a line after a statement, field definition, or enum value. + fn write_line_ending(&mut self, w: &mut W) -> fmt::Result; + + /// Separates consecutive items inside a block (e.g. between two field + /// definitions or two enum values that each have their own line). + fn write_block_item_separator(&mut self, w: &mut W) -> fmt::Result; + + /// Separates items in an inline comma-delimited list such as arguments, + /// variable definitions, or list-value elements. + fn write_list_separator(&mut self, w: &mut W) -> fmt::Result; + + /// Separates top-level definitions (types, directives, the schema block). + fn write_definition_separator(&mut self, w: &mut W) -> fmt::Result; + + /// Writes a GraphQL block-string description (`""" ... """`). + /// `depth` is the current nesting level. Implementations may choose to + /// omit descriptions entirely (as [`CompactFormatter`] does). + fn write_description( + &mut self, + w: &mut W, + desc: &str, + depth: usize, + ) -> fmt::Result; + + /// Opens an object-value literal (e.g. `{ ` in pretty mode, `{` in compact). + fn begin_value_object(&mut self, w: &mut W) -> fmt::Result; + + /// Closes an object-value literal (e.g. ` }` in pretty mode, `}` in compact). + fn end_value_object(&mut self, w: &mut W) -> fmt::Result; + + /// Writes the space (or other whitespace) that appears before an opening + /// brace-delimited block. Called immediately before [`begin_block`](Formatter::begin_block). + fn write_space_before_block(&mut self, w: &mut W) -> fmt::Result; + + /// Writes the separator between a key and its value (e.g. `": "` in pretty + /// mode, `":"` in compact). Used for type annotations, argument key-value + /// pairs, object value entries, field aliases, and variable definitions. + fn write_key_value_separator(&mut self, w: &mut W) -> fmt::Result; + + /// Writes the separator between union members or directive locations + /// (e.g. `" | "` in pretty mode, `"|"` in compact). + fn write_union_separator(&mut self, w: &mut W) -> fmt::Result; + + /// Writes the `=` separator used in default values and union type definitions + /// (e.g. `" = "` in pretty mode, `"="` in compact). + fn write_equals(&mut self, w: &mut W) -> fmt::Result; +} + +#[derive(Debug, Clone)] +pub struct PrettyFormatter { + indent_size: usize, +} + +impl PrettyFormatter { + pub fn new(indent_size: usize) -> Self { + Self { indent_size } + } +} + +impl Default for PrettyFormatter { + fn default() -> Self { + Self { indent_size: 2 } + } +} + +impl Formatter for PrettyFormatter { + fn write_indent(&mut self, w: &mut W, depth: usize) -> fmt::Result { + let chars = depth * self.indent_size; + write!(w, "{: >1$}", "", chars) + } + + fn begin_block(&mut self, w: &mut W, _depth: usize) -> fmt::Result { + writeln!(w, "{{") + } + + fn end_block(&mut self, w: &mut W, depth: usize) -> fmt::Result { + self.write_indent(w, depth)?; + write!(w, "}}") + } + + fn write_line_ending(&mut self, w: &mut W) -> fmt::Result { + writeln!(w) + } + + fn write_block_item_separator(&mut self, w: &mut W) -> fmt::Result { + writeln!(w) + } + + fn write_list_separator(&mut self, w: &mut W) -> fmt::Result { + write!(w, ", ") + } + + fn write_definition_separator(&mut self, w: &mut W) -> fmt::Result { + writeln!(w) + } + + fn write_description( + &mut self, + w: &mut W, + desc: &str, + depth: usize, + ) -> fmt::Result { + let chars = depth * self.indent_size; + write!(w, "{: >1$}", "", chars)?; + writeln!(w, "\"\"\"")?; + + let escaped = escape_block_string(desc); + + for line in escaped.lines() { + write!(w, "{: >1$}", "", chars)?; + writeln!(w, "{line}")?; + } + + write!(w, "{: >1$}", "", chars)?; + writeln!(w, "\"\"\"") + } + + fn begin_value_object(&mut self, w: &mut W) -> fmt::Result { + write!(w, "{{ ") + } + + fn end_value_object(&mut self, w: &mut W) -> fmt::Result { + write!(w, " }}") + } + + fn write_space_before_block(&mut self, w: &mut W) -> fmt::Result { + write!(w, " ") + } + + fn write_key_value_separator(&mut self, w: &mut W) -> fmt::Result { + write!(w, ": ") + } + + fn write_union_separator(&mut self, w: &mut W) -> fmt::Result { + write!(w, " | ") + } + + fn write_equals(&mut self, w: &mut W) -> fmt::Result { + write!(w, " = ") + } +} + +#[derive(Debug, Clone, Default)] +pub struct CompactFormatter; + +impl Formatter for CompactFormatter { + fn write_indent(&mut self, _w: &mut W, _depth: usize) -> fmt::Result { + Ok(()) + } + + fn begin_block(&mut self, w: &mut W, _depth: usize) -> fmt::Result { + write!(w, "{{") + } + + fn end_block(&mut self, w: &mut W, _depth: usize) -> fmt::Result { + write!(w, "}}") + } + + fn write_line_ending(&mut self, _w: &mut W) -> fmt::Result { + Ok(()) + } + + fn write_block_item_separator(&mut self, w: &mut W) -> fmt::Result { + write!(w, " ") + } + + fn write_list_separator(&mut self, w: &mut W) -> fmt::Result { + write!(w, ",") + } + + fn write_definition_separator(&mut self, w: &mut W) -> fmt::Result { + write!(w, " ") + } + + fn write_description( + &mut self, + _w: &mut W, + _desc: &str, + _depth: usize, + ) -> fmt::Result { + Ok(()) + } + + fn begin_value_object(&mut self, w: &mut W) -> fmt::Result { + write!(w, "{{") + } + + fn end_value_object(&mut self, w: &mut W) -> fmt::Result { + write!(w, "}}") + } + + fn write_space_before_block(&mut self, _w: &mut W) -> fmt::Result { + Ok(()) + } + + fn write_key_value_separator(&mut self, w: &mut W) -> fmt::Result { + write!(w, ":") + } + + fn write_union_separator(&mut self, w: &mut W) -> fmt::Result { + write!(w, "|") + } + + fn write_equals(&mut self, w: &mut W) -> fmt::Result { + write!(w, "=") + } +} diff --git a/bluejay-printer/src/lib.rs b/bluejay-printer/src/lib.rs index 849ad797..de7de2bf 100644 --- a/bluejay-printer/src/lib.rs +++ b/bluejay-printer/src/lib.rs @@ -1,14 +1,28 @@ -mod argument; -pub mod definition; -mod directive; -pub mod executable; -mod string_value; -pub mod value; +pub mod format; +pub mod serializer; -use std::fmt::{Error, Write}; +pub use format::{escape_block_string, CompactFormatter, Formatter, PrettyFormatter}; +pub use serializer::Serializer; -fn write_indent(f: &mut W, indentation: usize) -> Result<(), Error> { - write!(f, "{: >1$}", "", indentation) +use bluejay_core::definition::SchemaDefinition; +use bluejay_core::executable::ExecutableDocument; +use bluejay_core::Value; + +pub fn print_schema_definition(schema_definition: &S) -> String { + let mut s = Serializer::to_string(PrettyFormatter::default()); + s.serialize_schema_definition(schema_definition).unwrap(); + s.into_inner() +} + +pub fn print_executable_document(executable_document: &T) -> String { + let mut s = Serializer::to_string(PrettyFormatter::default()); + s.serialize_executable_document(executable_document) + .unwrap(); + s.into_inner() } -const INDENTATION_SIZE: usize = 2; +pub fn print_value>(value: &V) -> String { + let mut s = Serializer::to_string(PrettyFormatter::default()); + s.serialize_value(value).unwrap(); + s.into_inner() +} diff --git a/bluejay-printer/src/serializer.rs b/bluejay-printer/src/serializer.rs new file mode 100644 index 00000000..ec50b94e --- /dev/null +++ b/bluejay-printer/src/serializer.rs @@ -0,0 +1,1002 @@ +use crate::format::Formatter; +use bluejay_core::definition::HasDirectives; +use bluejay_core::definition::{ + ArgumentsDefinition, DirectiveDefinition, EnumTypeDefinition, EnumValueDefinition, + FieldDefinition, FieldsDefinition, InputObjectTypeDefinition, InputType, InputValueDefinition, + InterfaceImplementation, InterfaceImplementations, InterfaceTypeDefinition, + ObjectTypeDefinition, OutputType, ScalarTypeDefinition, SchemaDefinition, + TypeDefinitionReference, UnionMemberType, UnionTypeDefinition, +}; +use bluejay_core::executable::{ + ExecutableDocument, Field, FragmentDefinition, FragmentSpread, InlineFragment, + OperationDefinition, Selection, SelectionReference, SelectionSet, VariableDefinition, + VariableDefinitions, VariableType, +}; +use bluejay_core::{ + Argument, Arguments, AsIter, Directive, Directives, ObjectValue, Value, ValueReference, + Variable, +}; +use std::fmt; + +pub struct Serializer { + writer: W, + formatter: F, +} + +impl Serializer { + pub fn to_string(formatter: F) -> Self { + Self::new(String::new(), formatter) + } +} + +impl Serializer { + pub fn new(writer: W, formatter: F) -> Self { + Self { writer, formatter } + } + + pub fn into_inner(self) -> W { + self.writer + } + + // ── Value serialization ────────────────────────────────────────── + + pub fn serialize_value>( + &mut self, + value: &V, + ) -> fmt::Result { + match value.as_ref() { + ValueReference::Boolean(b) => write!(self.writer, "{b}"), + ValueReference::Enum(e) => write!(self.writer, "{e}"), + ValueReference::Float(fl) => { + if fl.fract().abs() < 1e-10 { + write!(self.writer, "{fl:.1}") + } else { + write!(self.writer, "{fl}") + } + } + ValueReference::Integer(i) => write!(self.writer, "{i}"), + ValueReference::List(l) => { + write!(self.writer, "[")?; + for (idx, el) in l.iter().enumerate() { + if idx != 0 { + self.formatter.write_list_separator(&mut self.writer)?; + } + self.serialize_value(el)?; + } + write!(self.writer, "]") + } + ValueReference::Null => write!(self.writer, "null"), + ValueReference::Object(o) => { + self.formatter.begin_value_object(&mut self.writer)?; + for (idx, (key, value)) in o.iter().enumerate() { + if idx != 0 { + self.formatter.write_list_separator(&mut self.writer)?; + } + write!(self.writer, "{}", key.as_ref())?; + self.formatter.write_key_value_separator(&mut self.writer)?; + self.serialize_value(value)?; + } + self.formatter.end_value_object(&mut self.writer) + } + ValueReference::String(s) => self.serialize_string_value(s), + ValueReference::Variable(v) => write!(self.writer, "${}", v.name()), + } + } + + fn serialize_string_value(&mut self, value: &str) -> fmt::Result { + write!(self.writer, "\"")?; + for c in value.chars() { + match c { + '\"' | '\\' => write!(self.writer, "\\{c}")?, + '\u{0008}' => write!(self.writer, "\\b")?, + '\u{000C}' => write!(self.writer, "\\f")?, + '\n' => write!(self.writer, "\\n")?, + '\r' => write!(self.writer, "\\r")?, + '\t' => write!(self.writer, "\\t")?, + c => write!(self.writer, "{c}")?, + } + } + write!(self.writer, "\"") + } + + // ── Argument serialization ─────────────────────────────────────── + + fn serialize_argument>( + &mut self, + argument: &A, + ) -> fmt::Result { + write!(self.writer, "{}", argument.name())?; + self.formatter.write_key_value_separator(&mut self.writer)?; + self.serialize_value(argument.value()) + } + + fn serialize_arguments>( + &mut self, + arguments: &A, + ) -> fmt::Result { + if arguments.is_empty() { + return Ok(()); + } + write!(self.writer, "(")?; + for (idx, argument) in arguments.iter().enumerate() { + if idx != 0 { + self.formatter.write_list_separator(&mut self.writer)?; + } + self.serialize_argument(argument)?; + } + write!(self.writer, ")") + } + + // ── Directive serialization ────────────────────────────────────── + + fn serialize_directive>( + &mut self, + directive: &D, + ) -> fmt::Result { + write!(self.writer, "@{}", directive.name())?; + if let Some(arguments) = directive.arguments() { + self.serialize_arguments(arguments)?; + } + Ok(()) + } + + fn serialize_directives>( + &mut self, + directives: &D, + ) -> fmt::Result { + for directive in directives.iter() { + write!(self.writer, " ")?; + self.serialize_directive(directive)?; + } + Ok(()) + } + + // ── Schema definition serialization ────────────────────────────── + + pub fn serialize_schema_definition( + &mut self, + schema_definition: &S, + ) -> fmt::Result { + let mut had_directives = false; + for (idx, dd) in schema_definition + .directive_definitions() + .filter(|dd| !dd.is_builtin()) + .enumerate() + { + if idx != 0 { + self.formatter + .write_definition_separator(&mut self.writer)?; + } + self.serialize_directive_definition(dd)?; + had_directives = true; + } + + let mut had_types = false; + for (idx, tdr) in schema_definition + .type_definitions() + .filter(|tdr| !tdr.is_builtin()) + .enumerate() + { + if had_directives || idx != 0 { + self.formatter + .write_definition_separator(&mut self.writer)?; + } + match tdr { + TypeDefinitionReference::BuiltinScalar(_) => {} + TypeDefinitionReference::CustomScalar(cstd) => { + self.serialize_scalar_type_definition(cstd)?; + } + TypeDefinitionReference::Enum(etd) => { + self.serialize_enum_type_definition(etd)?; + } + TypeDefinitionReference::InputObject(iotd) => { + self.serialize_input_object_type_definition(iotd)?; + } + TypeDefinitionReference::Interface(itd) => { + self.serialize_interface_type_definition(itd)?; + } + TypeDefinitionReference::Object(otd) => { + self.serialize_object_type_definition(otd)?; + } + TypeDefinitionReference::Union(utd) => { + self.serialize_union_type_definition(utd)?; + } + } + had_types = true; + } + + if !Self::is_schema_implicit(schema_definition) { + if had_directives || had_types { + self.formatter + .write_definition_separator(&mut self.writer)?; + } + self.serialize_explicit_schema_definition(schema_definition)?; + } + + Ok(()) + } + + fn is_schema_implicit(schema_definition: &S) -> bool { + schema_definition.description().is_none() + && schema_definition.query().name() == "Query" + && schema_definition + .mutation() + .map(|mutation| mutation.name() == "Mutation") + .unwrap_or(true) + && schema_definition + .subscription() + .map(|subscription| subscription.name() == "Subscription") + .unwrap_or(true) + && schema_definition + .directives() + .map(AsIter::is_empty) + .unwrap_or(true) + } + + fn serialize_explicit_schema_definition( + &mut self, + schema_definition: &S, + ) -> fmt::Result { + if let Some(description) = schema_definition.description() { + self.formatter + .write_description(&mut self.writer, description, 0)?; + } + + write!(self.writer, "schema")?; + + if let Some(directives) = schema_definition.directives() { + self.serialize_directives(directives)?; + } + + self.formatter.write_space_before_block(&mut self.writer)?; + self.formatter.begin_block(&mut self.writer, 0)?; + self.formatter.write_indent(&mut self.writer, 1)?; + write!(self.writer, "query: {}", schema_definition.query().name())?; + self.formatter.write_line_ending(&mut self.writer)?; + + if let Some(mutation) = schema_definition.mutation() { + self.formatter + .write_block_item_separator(&mut self.writer)?; + self.formatter.write_indent(&mut self.writer, 1)?; + write!(self.writer, "mutation: {}", mutation.name())?; + self.formatter.write_line_ending(&mut self.writer)?; + } + + if let Some(subscription) = schema_definition.subscription() { + self.formatter + .write_block_item_separator(&mut self.writer)?; + self.formatter.write_indent(&mut self.writer, 1)?; + write!(self.writer, "subscription: {}", subscription.name())?; + self.formatter.write_line_ending(&mut self.writer)?; + } + + self.formatter.end_block(&mut self.writer, 0)?; + self.formatter.write_line_ending(&mut self.writer) + } + + // ── Scalar type definition ─────────────────────────────────────── + + fn serialize_scalar_type_definition( + &mut self, + scalar: &S, + ) -> fmt::Result { + if let Some(description) = scalar.description() { + self.formatter + .write_description(&mut self.writer, description, 0)?; + } + + write!(self.writer, "scalar {}", scalar.name())?; + + if let Some(directives) = scalar.directives() { + self.serialize_directives(directives)?; + } + + self.formatter.write_line_ending(&mut self.writer) + } + + // ── Object type definition ─────────────────────────────────────── + + fn serialize_object_type_definition( + &mut self, + otd: &O, + ) -> fmt::Result { + if let Some(description) = otd.description() { + self.formatter + .write_description(&mut self.writer, description, 0)?; + } + + write!(self.writer, "type {}", otd.name())?; + + if let Some(interface_implementations) = otd.interface_implementations() { + self.serialize_interface_implementations(interface_implementations)?; + } + + if let Some(directives) = otd.directives() { + self.serialize_directives(directives)?; + } + + self.formatter.write_space_before_block(&mut self.writer)?; + self.serialize_fields_definition(otd.fields_definition()) + } + + // ── Interface type definition ──────────────────────────────────── + + fn serialize_interface_type_definition( + &mut self, + itd: &I, + ) -> fmt::Result { + if let Some(description) = itd.description() { + self.formatter + .write_description(&mut self.writer, description, 0)?; + } + + write!(self.writer, "interface {}", itd.name())?; + + if let Some(interface_implementations) = itd.interface_implementations() { + self.serialize_interface_implementations(interface_implementations)?; + } + + if let Some(directives) = itd.directives() { + self.serialize_directives(directives)?; + } + + self.formatter.write_space_before_block(&mut self.writer)?; + self.serialize_fields_definition(itd.fields_definition()) + } + + // ── Union type definition ──────────────────────────────────────── + + fn serialize_union_type_definition(&mut self, utd: &U) -> fmt::Result { + if let Some(description) = utd.description() { + self.formatter + .write_description(&mut self.writer, description, 0)?; + } + + write!(self.writer, "union {}", utd.name())?; + + if let Some(directives) = utd.directives() { + self.serialize_directives(directives)?; + } + + self.formatter.write_equals(&mut self.writer)?; + + for (idx, union_member) in utd.union_member_types().iter().enumerate() { + if idx != 0 { + self.formatter.write_union_separator(&mut self.writer)?; + } + write!(self.writer, "{}", union_member.name())?; + } + + self.formatter.write_line_ending(&mut self.writer) + } + + // ── Enum type definition ───────────────────────────────────────── + + fn serialize_enum_type_definition(&mut self, etd: &E) -> fmt::Result { + if let Some(description) = etd.description() { + self.formatter + .write_description(&mut self.writer, description, 0)?; + } + + write!(self.writer, "enum {}", etd.name())?; + + if let Some(directives) = etd.directives() { + self.serialize_directives(directives)?; + } + + self.formatter.write_space_before_block(&mut self.writer)?; + self.formatter.begin_block(&mut self.writer, 0)?; + + for (idx, evd) in etd.enum_value_definitions().iter().enumerate() { + if idx != 0 { + self.formatter + .write_block_item_separator(&mut self.writer)?; + } + + if let Some(description) = evd.description() { + self.formatter + .write_description(&mut self.writer, description, 1)?; + } + + self.formatter.write_indent(&mut self.writer, 1)?; + write!(self.writer, "{}", evd.name())?; + + if let Some(directives) = evd.directives() { + self.serialize_directives(directives)?; + } + + self.formatter.write_line_ending(&mut self.writer)?; + } + + self.formatter.end_block(&mut self.writer, 0)?; + self.formatter.write_line_ending(&mut self.writer) + } + + // ── Input object type definition ───────────────────────────────── + + fn serialize_input_object_type_definition( + &mut self, + iotd: &I, + ) -> fmt::Result { + if let Some(description) = iotd.description() { + self.formatter + .write_description(&mut self.writer, description, 0)?; + } + + write!(self.writer, "input {}", iotd.name())?; + + if let Some(directives) = iotd.directives() { + self.serialize_directives(directives)?; + } + + self.formatter.write_space_before_block(&mut self.writer)?; + self.formatter.begin_block(&mut self.writer, 0)?; + + for (idx, ivd) in iotd.input_field_definitions().iter().enumerate() { + if idx != 0 { + self.formatter + .write_block_item_separator(&mut self.writer)?; + } + self.serialize_input_value_definition(ivd, 1)?; + } + + self.formatter.end_block(&mut self.writer, 0)?; + self.formatter.write_line_ending(&mut self.writer) + } + + // ── Field definition ───────────────────────────────────────────── + + fn serialize_field_definition( + &mut self, + fd: &FD, + depth: usize, + ) -> fmt::Result { + if let Some(description) = fd.description() { + self.formatter + .write_description(&mut self.writer, description, depth)?; + } + + self.formatter.write_indent(&mut self.writer, depth)?; + write!(self.writer, "{}", fd.name())?; + + if let Some(arguments_definition) = fd.arguments_definition() { + self.serialize_arguments_definition(arguments_definition, depth)?; + } + + self.formatter.write_key_value_separator(&mut self.writer)?; + write!(self.writer, "{}", fd.r#type().display_name())?; + + if let Some(directives) = fd.directives() { + self.serialize_directives(directives)?; + } + + self.formatter.write_line_ending(&mut self.writer) + } + + fn serialize_fields_definition( + &mut self, + fields_definition: &FD, + ) -> fmt::Result { + self.formatter.begin_block(&mut self.writer, 0)?; + + for (idx, fd) in fields_definition + .iter() + .filter(|fd| !fd.is_builtin()) + .enumerate() + { + if idx != 0 { + self.formatter + .write_block_item_separator(&mut self.writer)?; + } + self.serialize_field_definition(fd, 1)?; + } + + self.formatter.end_block(&mut self.writer, 0)?; + self.formatter.write_line_ending(&mut self.writer) + } + + // ── Input value definition ─────────────────────────────────────── + + fn serialize_input_value_definition( + &mut self, + ivd: &I, + depth: usize, + ) -> fmt::Result { + if let Some(description) = ivd.description() { + self.formatter + .write_description(&mut self.writer, description, depth)?; + } + + self.formatter.write_indent(&mut self.writer, depth)?; + write!(self.writer, "{}", ivd.name())?; + self.formatter.write_key_value_separator(&mut self.writer)?; + write!(self.writer, "{}", ivd.r#type().display_name())?; + + if let Some(default_value) = ivd.default_value() { + self.formatter.write_equals(&mut self.writer)?; + self.serialize_value(default_value)?; + } + + if let Some(directives) = ivd.directives() { + self.serialize_directives(directives)?; + } + + self.formatter.write_line_ending(&mut self.writer) + } + + // ── Arguments definition ───────────────────────────────────────── + + fn serialize_arguments_definition( + &mut self, + arguments_definition: &AD, + depth: usize, + ) -> fmt::Result { + if arguments_definition.is_empty() { + return Ok(()); + } + + write!(self.writer, "(")?; + self.formatter.write_line_ending(&mut self.writer)?; + + for (idx, ivd) in arguments_definition.iter().enumerate() { + if idx != 0 { + self.formatter + .write_block_item_separator(&mut self.writer)?; + } + self.serialize_input_value_definition(ivd, depth + 1)?; + } + + self.formatter.write_indent(&mut self.writer, depth)?; + write!(self.writer, ")") + } + + // ── Directive definition ───────────────────────────────────────── + + fn serialize_directive_definition(&mut self, dd: &DD) -> fmt::Result { + if let Some(description) = dd.description() { + self.formatter + .write_description(&mut self.writer, description, 0)?; + } + + write!(self.writer, "directive @{}", dd.name())?; + + if let Some(arguments_definition) = dd.arguments_definition() { + self.serialize_arguments_definition(arguments_definition, 0)?; + } + + if dd.is_repeatable() { + write!(self.writer, " repeatable")?; + } + + write!(self.writer, " on ")?; + + for (idx, location) in dd.locations().iter().enumerate() { + if idx != 0 { + self.formatter.write_union_separator(&mut self.writer)?; + } + write!(self.writer, "{location}")?; + } + + self.formatter.write_line_ending(&mut self.writer) + } + + // ── Interface implementations ──────────────────────────────────── + + fn serialize_interface_implementations( + &mut self, + interface_implementations: &II, + ) -> fmt::Result { + if !interface_implementations.is_empty() { + write!(self.writer, " implements ")?; + for (idx, ii) in interface_implementations.iter().enumerate() { + if idx != 0 { + write!(self.writer, " & ")?; + } + write!(self.writer, "{}", ii.name())?; + } + } + Ok(()) + } + + // ── Executable document serialization ──────────────────────────── + + pub fn serialize_executable_document(&mut self, doc: &T) -> fmt::Result { + for (idx, operation_definition) in doc.operation_definitions().enumerate() { + if idx != 0 { + self.formatter + .write_definition_separator(&mut self.writer)?; + } + self.serialize_operation_definition(operation_definition)?; + self.formatter.write_line_ending(&mut self.writer)?; + } + + for fragment_definition in doc.fragment_definitions() { + self.formatter + .write_definition_separator(&mut self.writer)?; + self.serialize_fragment_definition(fragment_definition)?; + self.formatter.write_line_ending(&mut self.writer)?; + } + + Ok(()) + } + + // ── Operation definition ───────────────────────────────────────── + + fn serialize_operation_definition( + &mut self, + operation_definition: &O, + ) -> fmt::Result { + let odr = operation_definition.as_ref(); + write!(self.writer, "{}", odr.operation_type())?; + if let Some(name) = odr.name() { + write!(self.writer, " {name}")?; + } + if let Some(variable_definitions) = odr.variable_definitions() { + self.serialize_variable_definitions(variable_definitions)?; + } + if let Some(directives) = odr.directives() { + self.serialize_directives(directives)?; + } + self.formatter.write_space_before_block(&mut self.writer)?; + self.serialize_selection_set(odr.selection_set(), 0) + } + + // ── Selection set ──────────────────────────────────────────────── + + fn serialize_selection_set( + &mut self, + selection_set: &SS, + depth: usize, + ) -> fmt::Result { + self.formatter.begin_block(&mut self.writer, depth)?; + for (idx, selection) in selection_set.iter().enumerate() { + if idx != 0 { + self.formatter + .write_block_item_separator(&mut self.writer)?; + } + self.serialize_selection(selection, depth + 1)?; + self.formatter.write_line_ending(&mut self.writer)?; + } + self.formatter.end_block(&mut self.writer, depth) + } + + // ── Selection ──────────────────────────────────────────────────── + + fn serialize_selection(&mut self, selection: &S, depth: usize) -> fmt::Result { + match selection.as_ref() { + SelectionReference::Field(field) => self.serialize_field(field, depth), + SelectionReference::FragmentSpread(fragment_spread) => { + self.serialize_fragment_spread(fragment_spread, depth) + } + SelectionReference::InlineFragment(inline_fragment) => { + self.serialize_inline_fragment(inline_fragment, depth) + } + } + } + + // ── Field (executable) ─────────────────────────────────────────── + + fn serialize_field(&mut self, field: &FE, depth: usize) -> fmt::Result { + self.formatter.write_indent(&mut self.writer, depth)?; + if let Some(alias) = field.alias() { + write!(self.writer, "{alias}")?; + self.formatter.write_key_value_separator(&mut self.writer)?; + } + write!(self.writer, "{}", field.name())?; + if let Some(arguments) = field.arguments() { + self.serialize_arguments(arguments)?; + } + if let Some(directives) = field.directives() { + self.serialize_directives(directives)?; + } + if let Some(selection_set) = field.selection_set() { + self.formatter.write_space_before_block(&mut self.writer)?; + self.serialize_selection_set(selection_set, depth)?; + } + Ok(()) + } + + // ── Fragment definition ────────────────────────────────────────── + + fn serialize_fragment_definition(&mut self, fd: &FD) -> fmt::Result { + write!( + self.writer, + "fragment {} on {}", + fd.name(), + fd.type_condition(), + )?; + self.formatter.write_space_before_block(&mut self.writer)?; + self.serialize_selection_set(fd.selection_set(), 0) + } + + // ── Fragment spread ────────────────────────────────────────────── + + fn serialize_fragment_spread( + &mut self, + fragment_spread: &FS, + depth: usize, + ) -> fmt::Result { + self.formatter.write_indent(&mut self.writer, depth)?; + write!(self.writer, "...{}", fragment_spread.name())?; + if let Some(directives) = fragment_spread.directives() { + self.serialize_directives(directives)?; + } + Ok(()) + } + + // ── Inline fragment ────────────────────────────────────────────── + + fn serialize_inline_fragment( + &mut self, + inline_fragment: &IF, + depth: usize, + ) -> fmt::Result { + self.formatter.write_indent(&mut self.writer, depth)?; + write!(self.writer, "...")?; + if let Some(type_condition) = inline_fragment.type_condition() { + write!(self.writer, " on {type_condition}")?; + } + if let Some(directives) = inline_fragment.directives() { + self.serialize_directives(directives)?; + } + self.formatter.write_space_before_block(&mut self.writer)?; + self.serialize_selection_set(inline_fragment.selection_set(), depth) + } + + // ── Variable definitions ───────────────────────────────────────── + + fn serialize_variable_definition(&mut self, vd: &VD) -> fmt::Result { + write!(self.writer, "${}", vd.variable())?; + self.formatter.write_key_value_separator(&mut self.writer)?; + write!(self.writer, "{}", vd.r#type().as_ref().display_name())?; + if let Some(default_value) = vd.default_value() { + self.formatter.write_equals(&mut self.writer)?; + self.serialize_value(default_value)?; + } + if let Some(directives) = vd.directives() { + self.serialize_directives(directives)?; + } + Ok(()) + } + + fn serialize_variable_definitions( + &mut self, + variable_definitions: &VD, + ) -> fmt::Result { + if !variable_definitions.is_empty() { + write!(self.writer, "(")?; + for (idx, vd) in variable_definitions.iter().enumerate() { + if idx != 0 { + self.formatter.write_list_separator(&mut self.writer)?; + } + self.serialize_variable_definition(vd)?; + } + write!(self.writer, ")")?; + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::format::{escape_block_string, CompactFormatter, PrettyFormatter}; + use bluejay_parser::ast::{ + definition::{DefinitionDocument, SchemaDefinition}, + Arguments, Directives, Parse, VariableValue, + }; + + macro_rules! assert_value_prints { + ($val:literal) => { + let parsed = VariableValue::parse($val).result.unwrap(); + let mut s = Serializer::to_string(PrettyFormatter::default()); + s.serialize_value(&parsed).unwrap(); + assert_eq!($val, s.into_inner()); + }; + ($out:literal, $in:literal) => { + let parsed = VariableValue::parse($in).result.unwrap(); + let mut s = Serializer::to_string(PrettyFormatter::default()); + s.serialize_value(&parsed).unwrap(); + assert_eq!($out, s.into_inner()); + }; + } + + #[test] + fn test_bool() { + assert_value_prints!("true"); + assert_value_prints!("false"); + } + + #[test] + fn test_enum() { + assert_value_prints!("ONE"); + } + + #[test] + fn test_float() { + assert_value_prints!("1.0"); + assert_value_prints!("3.14159"); + assert_value_prints!("-1.23456"); + assert_value_prints!("10000.0", "1e4"); + assert_value_prints!("0.0"); + } + + #[test] + fn test_int() { + assert_value_prints!("1"); + assert_value_prints!("0"); + assert_value_prints!("-100"); + } + + #[test] + fn test_list() { + assert_value_prints!("[1, 2, 3]"); + assert_value_prints!("[]"); + assert_value_prints!("[[]]"); + } + + #[test] + fn test_null() { + assert_value_prints!("null"); + } + + #[test] + fn test_object() { + assert_value_prints!("{ foo: 1, bar: 2 }"); + } + + #[test] + fn test_string() { + assert_value_prints!(r#""""#); + assert_value_prints!(r#""\"\\/\b\n\f\r\t""#, r#""\"\\\/\b\n\f\r\t""#); + assert_value_prints!(r#""🔥""#); + } + + #[test] + fn test_variable() { + assert_value_prints!("$foo"); + } + + #[test] + fn test_arguments() { + let s = "(a: 1, b: 2)"; + let parsed = Arguments::::parse(s).result.unwrap(); + let mut ser = Serializer::to_string(PrettyFormatter::default()); + ser.serialize_arguments(&parsed).unwrap(); + assert_eq!(s, ser.into_inner()); + } + + #[test] + fn test_directives() { + let s = " @foo(a: 1, b: 2) @bar"; + let parsed = Directives::::parse(s).result.unwrap(); + let mut ser = Serializer::to_string(PrettyFormatter::default()); + ser.serialize_directives(&parsed).unwrap(); + assert_eq!(s, ser.into_inner()); + } + + #[test] + fn test_block_string_value() { + fn write_desc(desc: &str, depth: usize) -> String { + let mut output = String::new(); + let mut fmt = PrettyFormatter::default(); + fmt.write_description(&mut output, desc, depth).unwrap(); + output + } + + assert_eq!("\"\"\"\n\"\"\"\n", write_desc("", 0)); + assert_eq!(" \"\"\"\n \"\"\"\n", write_desc("", 2)); + assert_eq!( + "\"\"\"\nThis\nis\na\nmultiline\nstring\n\"\"\"\n", + write_desc("This\nis\na\nmultiline\nstring", 0) + ); + assert_eq!("\"\"\"\n\\\"\"\"\n\"\"\"\n", write_desc("\"\"\"", 0)); + } + + #[test] + fn test_schema_dump() { + insta::glob!("definition/test_data/schema_definition/*.graphql", |path| { + let input = std::fs::read_to_string(path).unwrap(); + let document: DefinitionDocument = + DefinitionDocument::parse(input.as_str()).result.unwrap(); + let schema_definition = SchemaDefinition::try_from(&document).unwrap(); + let mut s = Serializer::to_string(PrettyFormatter::default()); + s.serialize_schema_definition(&schema_definition).unwrap(); + similar_asserts::assert_eq!(input, s.into_inner()); + }); + } + + // ── escape_block_string ───────────────────────────────────────── + + #[test] + fn test_escape_block_string() { + assert_eq!("hello", escape_block_string("hello")); + assert_eq!(r#"\""""#, escape_block_string(r#"""""#)); + assert_eq!( + r#"before \""" after"#, + escape_block_string(r#"before """ after"#) + ); + assert_eq!("no change", escape_block_string("no change")); + } + + // ── CompactFormatter tests ────────────────────────────────────── + + macro_rules! assert_compact_value_prints { + ($out:literal, $in:literal) => { + let parsed = VariableValue::parse($in).result.unwrap(); + let mut s = Serializer::to_string(CompactFormatter); + s.serialize_value(&parsed).unwrap(); + assert_eq!($out, s.into_inner()); + }; + } + + #[test] + fn test_compact_value_list() { + assert_compact_value_prints!("[1,2,3]", "[1, 2, 3]"); + } + + #[test] + fn test_compact_value_object() { + assert_compact_value_prints!("{foo:1,bar:2}", "{ foo: 1, bar: 2 }"); + } + + #[test] + fn test_compact_arguments() { + let s = "(a: 1, b: 2)"; + let parsed = Arguments::::parse(s).result.unwrap(); + let mut ser = Serializer::to_string(CompactFormatter); + ser.serialize_arguments(&parsed).unwrap(); + assert_eq!("(a:1,b:2)", ser.into_inner()); + } + + #[test] + fn test_compact_directives() { + let s = " @foo(a: 1, b: 2) @bar"; + let parsed = Directives::::parse(s).result.unwrap(); + let mut ser = Serializer::to_string(CompactFormatter); + ser.serialize_directives(&parsed).unwrap(); + assert_eq!(" @foo(a:1,b:2) @bar", ser.into_inner()); + } + + #[test] + fn test_compact_schema_definition() { + insta::glob!("definition/test_data/schema_definition/*.graphql", |path| { + let input = std::fs::read_to_string(path).unwrap(); + let document: DefinitionDocument = + DefinitionDocument::parse(input.as_str()).result.unwrap(); + let schema_definition = SchemaDefinition::try_from(&document).unwrap(); + let mut s = Serializer::to_string(CompactFormatter); + s.serialize_schema_definition(&schema_definition).unwrap(); + let compact = s.into_inner(); + insta::assert_snapshot!(compact.clone()); + + let reparsed_document: DefinitionDocument = DefinitionDocument::parse(compact.as_str()) + .result + .unwrap_or_else(|_| { + panic!("compact output failed to parse for {}", path.display()) + }); + SchemaDefinition::try_from(&reparsed_document).unwrap_or_else(|_| { + panic!( + "compact output failed to build schema definition for {}", + path.display() + ) + }); + }); + } + + // ── PrettyFormatter with custom indent ────────────────────────── + + #[test] + fn test_custom_indent_size() { + let input = "type Query {\n name: String!\n}\n"; + let document: DefinitionDocument = DefinitionDocument::parse(input).result.unwrap(); + let schema_definition = SchemaDefinition::try_from(&document).unwrap(); + let mut s = Serializer::to_string(PrettyFormatter::new(4)); + s.serialize_schema_definition(&schema_definition).unwrap(); + let output = s.into_inner(); + assert!( + output.contains(" name"), + "expected 4-space indent, got: {output}" + ); + } +} diff --git a/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@basic.graphql.snap b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@basic.graphql.snap new file mode 100644 index 00000000..c6a4e3db --- /dev/null +++ b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@basic.graphql.snap @@ -0,0 +1,6 @@ +--- +source: bluejay-printer/src/serializer.rs +expression: s.into_inner() +input_file: bluejay-printer/src/definition/test_data/schema_definition/basic.graphql +--- +input MyInput{intField:Int! booleanField:Boolean!} type MyObject{intField:Int! idField:ID!} type Query{myField(bar:MyInput!):MyObject! bar:[String!]!} diff --git a/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@directive.graphql.snap b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@directive.graphql.snap new file mode 100644 index 00000000..28ae346a --- /dev/null +++ b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@directive.graphql.snap @@ -0,0 +1,6 @@ +--- +source: bluejay-printer/src/serializer.rs +expression: s.into_inner() +input_file: bluejay-printer/src/definition/test_data/schema_definition/directive.graphql +--- +directive @repeatable repeatable on FIELD_DEFINITION directive @special on FIELD_DEFINITION type Query{specialField:String! @repeatable @special @repeatable} diff --git a/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@enum.graphql.snap b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@enum.graphql.snap new file mode 100644 index 00000000..f5bbfd39 --- /dev/null +++ b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@enum.graphql.snap @@ -0,0 +1,6 @@ +--- +source: bluejay-printer/src/serializer.rs +expression: s.into_inner() +input_file: bluejay-printer/src/definition/test_data/schema_definition/enum.graphql +--- +type Query{weight:Weight!} type Weight{value:Int! unit:WeightUnit!} enum WeightUnit{KILOGRAMS POUNDS} diff --git a/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@explicit_schema.graphql.snap b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@explicit_schema.graphql.snap new file mode 100644 index 00000000..133e5876 --- /dev/null +++ b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@explicit_schema.graphql.snap @@ -0,0 +1,6 @@ +--- +source: bluejay-printer/src/serializer.rs +expression: compact.clone() +input_file: bluejay-printer/src/definition/test_data/schema_definition/explicit_schema.graphql +--- +type MyMutationRootType{setSomeField(to:String):String} type MyQueryRootType{someField:String} schema{query: MyQueryRootType mutation: MyMutationRootType} diff --git a/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@interface.graphql.snap b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@interface.graphql.snap new file mode 100644 index 00000000..c773b687 --- /dev/null +++ b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@interface.graphql.snap @@ -0,0 +1,6 @@ +--- +source: bluejay-printer/src/serializer.rs +expression: s.into_inner() +input_file: bluejay-printer/src/definition/test_data/schema_definition/interface.graphql +--- +interface MyInterface{stringField:String!} interface MyOtherInterface implements MyInterface{intField:Int! stringField:String!} type MyType implements MyInterface & MyOtherInterface{intField:Int! stringField:String!} type Query{myField:MyType!} diff --git a/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@union.graphql.snap b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@union.graphql.snap new file mode 100644 index 00000000..ae2c3ffb --- /dev/null +++ b/bluejay-printer/src/snapshots/bluejay_printer__serializer__tests__compact_schema_definition@union.graphql.snap @@ -0,0 +1,6 @@ +--- +source: bluejay-printer/src/serializer.rs +expression: compact.clone() +input_file: bluejay-printer/src/definition/test_data/schema_definition/union.graphql +--- +type Person{name:String age:Int} type Photo{height:Int width:Int} type SearchQuery{firstSearchResult:SearchResult} union SearchResult=Photo|Person schema{query: SearchQuery} diff --git a/bluejay-printer/src/string_value.rs b/bluejay-printer/src/string_value.rs deleted file mode 100644 index b6e5c371..00000000 --- a/bluejay-printer/src/string_value.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::write_indent; -use std::fmt::{Display, Formatter, Result}; - -pub(crate) struct StringValuePrinter<'a>(&'a str); - -impl<'a> StringValuePrinter<'a> { - pub(crate) fn new(value: &'a str) -> Self { - Self(value) - } -} - -impl Display for StringValuePrinter<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(value) = *self; - write!(f, "\"")?; - value.chars().try_for_each(|c| match c { - '\"' | '\\' => write!(f, "\\{c}"), - '\u{0008}' => write!(f, "\\b"), - '\u{000C}' => write!(f, "\\f"), - '\n' => write!(f, "\\n"), - '\r' => write!(f, "\\r"), - '\t' => write!(f, "\\t"), - c => write!(f, "{c}"), - })?; - write!(f, "\"") - } -} - -pub(crate) struct BlockStringValuePrinter<'a> { - value: &'a str, - indentation: usize, -} - -impl<'a> BlockStringValuePrinter<'a> { - pub(crate) fn new(value: &'a str, indentation: usize) -> Self { - Self { value, indentation } - } -} - -impl Display for BlockStringValuePrinter<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self { value, indentation } = *self; - write_indent(f, indentation)?; - writeln!(f, "\"\"\"")?; - - let escaped = value.replace("\"\"\"", "\\\"\"\""); - - escaped.lines().try_for_each(|line| { - write_indent(f, indentation)?; - writeln!(f, "{line}") - })?; - - write_indent(f, indentation)?; - writeln!(f, "\"\"\"") - } -} - -#[cfg(test)] -mod tests { - use super::BlockStringValuePrinter; - - fn assert_prints_block(expected_output: &str, input: &str, indentation: usize) { - let output = BlockStringValuePrinter::new(input, indentation).to_string(); - assert_eq!(expected_output, output); - } - - #[test] - fn test_block() { - assert_prints_block("\"\"\"\n\"\"\"\n", "", 0); - assert_prints_block(" \"\"\"\n \"\"\"\n", "", 4); - assert_prints_block( - "\"\"\"\nThis\nis\na\nmultiline\nstring\n\"\"\"\n", - "This\nis\na\nmultiline\nstring", - 0, - ); - assert_prints_block("\"\"\"\n\\\"\"\"\n\"\"\"\n", "\"\"\"", 0); - } -} diff --git a/bluejay-printer/src/value.rs b/bluejay-printer/src/value.rs deleted file mode 100644 index 6a8a491a..00000000 --- a/bluejay-printer/src/value.rs +++ /dev/null @@ -1,131 +0,0 @@ -use crate::string_value::StringValuePrinter; -use bluejay_core::{AsIter, ObjectValue, Value, ValueReference, Variable}; -use std::fmt::{Display, Formatter, Result}; - -pub struct ValuePrinter<'a, const CONST: bool, V: Value>(&'a V); - -impl<'a, const CONST: bool, V: Value> ValuePrinter<'a, CONST, V> { - pub fn new(value: &'a V) -> Self { - Self(value) - } - - pub fn to_string(value: &'a V) -> String { - Self::new(value).to_string() - } -} - -impl> Display for ValuePrinter<'_, CONST, V> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - let Self(value) = *self; - match value.as_ref() { - ValueReference::Boolean(b) => write!(f, "{}", b), - ValueReference::Enum(e) => write!(f, "{}", e), - ValueReference::Float(fl) => { - if fl.fract().abs() < 1e-10 { - write!(f, "{fl:.1}") - } else { - write!(f, "{fl}") - } - } - ValueReference::Integer(i) => write!(f, "{}", i), - ValueReference::List(l) => { - write!(f, "[")?; - l.iter().enumerate().try_for_each(|(idx, el)| { - if idx != 0 { - write!(f, ", ")?; - } - write!(f, "{}", Self::new(el)) - })?; - write!(f, "]") - } - ValueReference::Null => write!(f, "null"), - ValueReference::Object(o) => { - write!(f, "{{ ")?; - - o.iter().enumerate().try_for_each(|(idx, (key, value))| { - if idx != 0 { - write!(f, ", ")?; - } - write!(f, "{}: {}", key.as_ref(), Self::new(value)) - })?; - - write!(f, " }}") - } - ValueReference::String(s) => write!(f, "{}", StringValuePrinter::new(s)), - ValueReference::Variable(v) => write!(f, "${}", v.name()), - } - } -} - -#[cfg(test)] -mod tests { - use super::ValuePrinter; - use bluejay_parser::ast::{Parse, VariableValue}; - - macro_rules! assert_prints { - ($val:literal) => { - let parsed = VariableValue::parse($val).result.unwrap(); - assert_eq!($val, ValuePrinter::new(&parsed).to_string()); - }; - ($out:literal, $in:literal) => { - let parsed = VariableValue::parse($in).result.unwrap(); - assert_eq!($out, ValuePrinter::new(&parsed).to_string()); - }; - } - - #[test] - fn test_bool() { - assert_prints!("true"); - assert_prints!("false"); - } - - #[test] - fn test_enum() { - assert_prints!("ONE"); - } - - #[test] - fn test_float() { - assert_prints!("1.0"); - assert_prints!("3.14159"); - assert_prints!("-1.23456"); - assert_prints!("10000.0", "1e4"); - assert_prints!("0.0"); - } - - #[test] - fn test_int() { - assert_prints!("1"); - assert_prints!("0"); - assert_prints!("-100"); - } - - #[test] - fn test_list() { - assert_prints!("[1, 2, 3]"); - assert_prints!("[]"); - assert_prints!("[[]]"); - } - - #[test] - fn test_null() { - assert_prints!("null"); - } - - #[test] - fn test_object() { - assert_prints!("{ foo: 1, bar: 2 }"); - } - - #[test] - fn test_string() { - assert_prints!(r#""""#); - assert_prints!(r#""\"\\/\b\n\f\r\t""#, r#""\"\\\/\b\n\f\r\t""#); - assert_prints!(r#""🔥""#); - } - - #[test] - fn test_variable() { - assert_prints!("$foo"); - } -} diff --git a/bluejay-printer/tests/integration_test.rs b/bluejay-printer/tests/integration_test.rs index e6c95511..df7971c3 100644 --- a/bluejay-printer/tests/integration_test.rs +++ b/bluejay-printer/tests/integration_test.rs @@ -3,7 +3,7 @@ use bluejay_parser::ast::{ executable::ExecutableDocument, Parse, }; -use bluejay_printer::{definition::SchemaDefinitionPrinter, executable::ExecutableDocumentPrinter}; +use bluejay_printer::{print_executable_document, print_schema_definition}; use similar_asserts::assert_eq; #[test] @@ -13,13 +13,13 @@ fn test_definition_printer() { DefinitionDocument::parse(s.as_str()).result.unwrap(); let original_schema_definition = SchemaDefinition::try_from(&original_document).unwrap(); - let printed = SchemaDefinitionPrinter::to_string(&original_schema_definition); + let printed = print_schema_definition(&original_schema_definition); insta::assert_snapshot!(printed); let printed_document: DefinitionDocument = DefinitionDocument::parse(printed.as_str()).result.unwrap(); let printed_schema_definition = SchemaDefinition::try_from(&printed_document).unwrap(); - let reprinted = SchemaDefinitionPrinter::to_string(&printed_schema_definition); + let reprinted = print_schema_definition(&printed_schema_definition); assert_eq!( original_document.definition_count(), @@ -35,7 +35,7 @@ fn test_executable_printer() { let executable_document = ExecutableDocument::parse(input.as_str()) .result .unwrap_or_else(|_| panic!("Document `{}` had parse errors", path.display())); - let printed = ExecutableDocumentPrinter::to_string(&executable_document); + let printed = print_executable_document(&executable_document); assert_eq!(input, printed); }); } diff --git a/bluejay-schema-comparator/src/changes.rs b/bluejay-schema-comparator/src/changes.rs index d88f1b12..36faa18b 100644 --- a/bluejay-schema-comparator/src/changes.rs +++ b/bluejay-schema-comparator/src/changes.rs @@ -6,7 +6,7 @@ use bluejay_core::definition::{ ShallowOutputTypeReference, TypeDefinitionReference, UnionTypeDefinition, }; use bluejay_core::{Argument, AsIter, Directive, Value}; -use bluejay_printer::value::ValuePrinter; +use bluejay_printer::print_value; use std::borrow::Cow; use strum::AsRefStr; @@ -523,7 +523,7 @@ impl Change<'_, S> { } => match (old_argument.default_value(), new_argument.default_value()) { (Some(old_default_value), Some(new_default_value)) => { if old_default_value.as_ref() != new_default_value.as_ref() { - format!("Default value for argument `{}` on field `{}.{}` was changed from `{}` to `{}`", old_argument.name(), type_name, field.name(), ValuePrinter::new(old_default_value), ValuePrinter::new(new_default_value)) + format!("Default value for argument `{}` on field `{}.{}` was changed from `{}` to `{}`", old_argument.name(), type_name, field.name(), print_value(old_default_value), print_value(new_default_value)) } else { String::new() } @@ -531,7 +531,7 @@ impl Change<'_, S> { (Some(old_default_value), None) => { format!( "Default value `{}` was removed from argument `{}` on field `{}.{}`", - ValuePrinter::new(old_default_value), + print_value(old_default_value), old_argument.name(), type_name, field.name() @@ -540,7 +540,7 @@ impl Change<'_, S> { (None, Some(new_default_value)) => { format!( "Default value `{}` was added to argument `{}` on field `{}.{}`", - ValuePrinter::new(new_default_value), + print_value(new_default_value), new_argument.name(), type_name, field.name() @@ -696,8 +696,8 @@ impl Change<'_, S> { "Input field `{}.{}` default value changed from `{}` to `{}`", input_object_type_definition.name(), new_field_definition.name(), - ValuePrinter::new(old_default_value), - ValuePrinter::new(new_default_value) + print_value(old_default_value), + print_value(new_default_value) ) } else { String::new() @@ -706,7 +706,7 @@ impl Change<'_, S> { (Some(old_default_value), None) => { format!( "Default value `{}` was removed from input field `{}.{}`", - ValuePrinter::new(old_default_value), + print_value(old_default_value), input_object_type_definition.name(), old_field_definition.name() ) @@ -714,7 +714,7 @@ impl Change<'_, S> { (None, Some(new_default_value)) => { format!( "Default value `{}` was added to input field `{}.{}`", - ValuePrinter::new(new_default_value), + print_value(new_default_value), input_object_type_definition.name(), old_field_definition.name() ) @@ -819,7 +819,7 @@ impl Change<'_, S> { ) { (Some(old_default_value), Some(new_default_value)) => { if old_default_value.as_ref() != new_default_value.as_ref() { - format!("Directive argument `{}.{}` default value changed from `{}` to `{}`", directive_definition.name(), new_argument_definition.name(), ValuePrinter::new(old_default_value), ValuePrinter::new(new_default_value)) + format!("Directive argument `{}.{}` default value changed from `{}` to `{}`", directive_definition.name(), new_argument_definition.name(), print_value(old_default_value), print_value(new_default_value)) } else { String::new() } @@ -827,7 +827,7 @@ impl Change<'_, S> { (Some(old_default_value), None) => { format!( "Default value `{}` was removed from directive argument `{}.{}`", - ValuePrinter::new(old_default_value), + print_value(old_default_value), directive_definition.name(), old_argument_definition.name() ) @@ -835,7 +835,7 @@ impl Change<'_, S> { (None, Some(new_default_value)) => { format!( "Default value `{}` was added to directive argument `{}.{}`", - ValuePrinter::new(new_default_value), + print_value(new_default_value), directive_definition.name(), old_argument_definition.name() ) @@ -896,8 +896,8 @@ impl Change<'_, S> { "Value for argument `{}` on directive `{}` changed from {} to {}", new_argument.name(), directive.name(), - ValuePrinter::new(old_argument.value()), - ValuePrinter::new(new_argument.value()), + print_value(old_argument.value()), + print_value(new_argument.value()), ) } } diff --git a/bluejay-visibility/tests/integration_test.rs b/bluejay-visibility/tests/integration_test.rs index 59f4f34d..8048f9f8 100644 --- a/bluejay-visibility/tests/integration_test.rs +++ b/bluejay-visibility/tests/integration_test.rs @@ -12,7 +12,7 @@ use bluejay_parser::{ }, Error, }; -use bluejay_printer::definition::SchemaDefinitionPrinter; +use bluejay_printer::print_schema_definition; use bluejay_visibility::{Cache, SchemaDefinition, Warden}; use std::marker::PhantomData; @@ -160,7 +160,7 @@ fn test_visibility() { let visibility_scoped_schema_definition = SchemaDefinition::new(&cache).unwrap(); let printed_schema_definition = - SchemaDefinitionPrinter::to_string(&visibility_scoped_schema_definition); + print_schema_definition(&visibility_scoped_schema_definition); insta::assert_snapshot!(printed_schema_definition); });