apollo_compiler/ast/
serialize.rs

1use super::*;
2use crate::executable;
3use crate::schema;
4use std::fmt;
5use std::fmt::Display;
6
7/// Builder pattern for GraphQL serialization configuration.
8/// Implements [`Display`] and [`ToString`].
9#[derive(Debug, Clone)]
10pub struct Serialize<'a, T> {
11    pub(crate) node: &'a T,
12    pub(crate) config: Config<'a>,
13}
14
15#[derive(Debug, Clone)]
16pub(crate) struct Config<'a> {
17    indent_prefix: Option<&'a str>,
18    initial_indent_level: usize,
19}
20
21pub(crate) struct State<'config, 'fmt, 'fmt2> {
22    config: Config<'config>,
23    indent_level: usize,
24    output: &'fmt mut fmt::Formatter<'fmt2>,
25    /// Have we not written anything yet?
26    output_empty: bool,
27}
28
29impl<'a, T> Serialize<'a, T> {
30    /// Enable indentation and line breaks.
31    ///
32    /// `prefix` is repeated at the start of each line by the number of indentation levels.
33    /// The default is `"  "`, two spaces.
34    pub fn indent_prefix(mut self, prefix: &'a str) -> Self {
35        self.config.indent_prefix = Some(prefix);
36        self
37    }
38
39    /// Disable indentation and line breaks
40    pub fn no_indent(mut self) -> Self {
41        self.config.indent_prefix = None;
42        self
43    }
44
45    pub fn initial_indent_level(mut self, initial_indent_level: usize) -> Self {
46        self.config.initial_indent_level = initial_indent_level;
47        self
48    }
49}
50
51impl Default for Config<'_> {
52    fn default() -> Self {
53        Self {
54            indent_prefix: Some("  "),
55            initial_indent_level: 0,
56        }
57    }
58}
59
60macro_rules! display {
61    ($state: expr, $e: expr) => {
62        fmt::Display::fmt(&$e, $state.output)
63    };
64    ($state: expr, $($tt: tt)+) => {
65        display!($state, format_args!($($tt)+))
66    };
67
68}
69
70impl State<'_, '_, '_> {
71    pub(crate) fn write(&mut self, str: &str) -> fmt::Result {
72        self.output_empty = false;
73        self.output.write_str(str)
74    }
75
76    pub(crate) fn indent(&mut self) -> fmt::Result {
77        self.indent_level += 1;
78        self.new_line_common(false)
79    }
80
81    pub(crate) fn indent_or_space(&mut self) -> fmt::Result {
82        self.indent_level += 1;
83        self.new_line_common(true)
84    }
85
86    pub(crate) fn dedent(&mut self) -> fmt::Result {
87        self.indent_level -= 1; // checked underflow in debug mode
88        self.new_line_common(false)
89    }
90
91    pub(crate) fn dedent_or_space(&mut self) -> fmt::Result {
92        self.indent_level -= 1; // checked underflow in debug mode
93        self.new_line_common(true)
94    }
95
96    pub(crate) fn new_line_or_space(&mut self) -> fmt::Result {
97        self.new_line_common(true)
98    }
99
100    fn new_line_common(&mut self, space: bool) -> fmt::Result {
101        if let Some(prefix) = self.config.indent_prefix {
102            self.write("\n")?;
103            for _ in 0..self.indent_level {
104                self.write(prefix)?;
105            }
106        } else if space {
107            self.write(" ")?
108        }
109        Ok(())
110    }
111
112    /// Panics if newlines are disabled
113    fn require_new_line(&mut self) -> fmt::Result {
114        let prefix = self
115            .config
116            .indent_prefix
117            .expect("require_new_line called with newlines disabled");
118        self.write("\n")?;
119        for _ in 0..self.indent_level {
120            self.write(prefix)?;
121        }
122        Ok(())
123    }
124
125    pub(crate) fn newlines_enabled(&self) -> bool {
126        self.config.indent_prefix.is_some()
127    }
128
129    pub(crate) fn on_single_line<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
130        let indent_prefix = self.config.indent_prefix.take();
131        let result = f(self);
132        self.config.indent_prefix = indent_prefix;
133        result
134    }
135}
136
137impl Document {
138    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
139        top_level(state, &self.definitions, |state, def| {
140            def.serialize_impl(state)
141        })
142    }
143}
144
145pub(crate) fn top_level<T>(
146    state: &mut State,
147    iter: impl IntoIterator<Item = T>,
148    serialize_one: impl Fn(&mut State, T) -> fmt::Result,
149) -> fmt::Result {
150    let mut iter = iter.into_iter();
151    if let Some(first) = iter.next() {
152        serialize_one(state, first)?;
153        iter.try_for_each(|item| {
154            if state.newlines_enabled() {
155                // Empty line between top-level definitions
156                state.write("\n")?;
157            }
158            state.new_line_or_space()?;
159            serialize_one(state, item)
160        })?;
161        // Trailing newline
162        if state.newlines_enabled() {
163            state.write("\n")?;
164        }
165    }
166    Ok(())
167}
168
169impl Definition {
170    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
171        match self {
172            Definition::OperationDefinition(def) => def.serialize_impl(state),
173            Definition::FragmentDefinition(def) => def.serialize_impl(state),
174            Definition::DirectiveDefinition(def) => def.serialize_impl(state),
175            Definition::SchemaDefinition(def) => def.serialize_impl(state),
176            Definition::ScalarTypeDefinition(def) => def.serialize_impl(state),
177            Definition::ObjectTypeDefinition(def) => def.serialize_impl(state),
178            Definition::InterfaceTypeDefinition(def) => def.serialize_impl(state),
179            Definition::UnionTypeDefinition(def) => def.serialize_impl(state),
180            Definition::EnumTypeDefinition(def) => def.serialize_impl(state),
181            Definition::InputObjectTypeDefinition(def) => def.serialize_impl(state),
182            Definition::SchemaExtension(def) => def.serialize_impl(state),
183            Definition::ScalarTypeExtension(def) => def.serialize_impl(state),
184            Definition::ObjectTypeExtension(def) => def.serialize_impl(state),
185            Definition::InterfaceTypeExtension(def) => def.serialize_impl(state),
186            Definition::UnionTypeExtension(def) => def.serialize_impl(state),
187            Definition::EnumTypeExtension(def) => def.serialize_impl(state),
188            Definition::InputObjectTypeExtension(def) => def.serialize_impl(state),
189        }
190    }
191}
192
193impl OperationDefinition {
194    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
195        // Deconstruct to get a warning if we forget to serialize something
196        let Self {
197            operation_type,
198            name,
199            variables,
200            directives,
201            selection_set,
202        } = self;
203        // Only use shorthand when this is the first item.
204        // If not, it might be following a `[lookahead != "{"]` grammar production
205        let shorthand = state.output_empty
206            && *operation_type == OperationType::Query
207            && name.is_none()
208            && variables.is_empty()
209            && directives.is_empty();
210        if !shorthand {
211            state.write(operation_type.name())?;
212            if let Some(name) = &name {
213                state.write(" ")?;
214                state.write(name)?;
215            }
216            if !variables.is_empty() {
217                state.on_single_line(|state| {
218                    comma_separated(state, "(", ")", variables, |state, var| {
219                        var.serialize_impl(state)
220                    })
221                })?
222            }
223            directives.serialize_impl(state)?;
224            state.write(" ")?;
225        }
226        curly_brackets_space_separated(state, selection_set, |state, sel| sel.serialize_impl(state))
227    }
228}
229
230impl FragmentDefinition {
231    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
232        let Self {
233            name,
234            type_condition,
235            directives,
236            selection_set,
237        } = self;
238        display!(state, "fragment {} on {}", name, type_condition)?;
239        directives.serialize_impl(state)?;
240        state.write(" ")?;
241        curly_brackets_space_separated(state, selection_set, |state, sel| sel.serialize_impl(state))
242    }
243}
244
245impl DirectiveDefinition {
246    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
247        let Self {
248            description,
249            name,
250            arguments,
251            repeatable,
252            locations,
253        } = self;
254        serialize_description(state, description)?;
255        state.write("directive @")?;
256        state.write(name)?;
257        serialize_arguments_definition(state, arguments)?;
258
259        if *repeatable {
260            state.write(" repeatable")?;
261        }
262        if let Some((first, rest)) = locations.split_first() {
263            state.write(" on ")?;
264            state.write(first.name())?;
265            for location in rest {
266                state.write(" | ")?;
267                state.write(location.name())?;
268            }
269        }
270        Ok(())
271    }
272}
273
274fn serialize_arguments_definition(
275    state: &mut State,
276    arguments: &[Node<InputValueDefinition>],
277) -> fmt::Result {
278    if !arguments.is_empty() {
279        let serialize_arguments = |state: &mut State| {
280            comma_separated(state, "(", ")", arguments, |state, arg| {
281                arg.serialize_impl(state)
282            })
283        };
284        if arguments
285            .iter()
286            .any(|arg| arg.description.is_some() || !arg.directives.is_empty())
287        {
288            serialize_arguments(state)?
289        } else {
290            state.on_single_line(serialize_arguments)?
291        }
292    }
293    Ok(())
294}
295
296impl SchemaDefinition {
297    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
298        let Self {
299            description,
300            directives,
301            root_operations,
302        } = self;
303        serialize_description(state, description)?;
304        state.write("schema")?;
305        directives.serialize_impl(state)?;
306        state.write(" ")?;
307        curly_brackets_space_separated(state, root_operations, |state, op| {
308            let (operation_type, operation_name) = &**op;
309            display!(state, "{}: {}", operation_type, operation_name)
310        })
311    }
312}
313
314impl ScalarTypeDefinition {
315    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
316        let Self {
317            description,
318            name,
319            directives,
320        } = self;
321        serialize_description(state, description)?;
322        state.write("scalar ")?;
323        state.write(name)?;
324        directives.serialize_impl(state)
325    }
326}
327
328impl ObjectTypeDefinition {
329    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
330        let Self {
331            description,
332            name,
333            implements_interfaces,
334            directives,
335            fields,
336        } = self;
337        serialize_description(state, description)?;
338        state.write("type ")?;
339        serialize_object_type_like(state, name, implements_interfaces, directives, fields)
340    }
341}
342
343fn serialize_object_type_like(
344    state: &mut State,
345    name: &str,
346    implements_interfaces: &[Name],
347    directives: &DirectiveList,
348    fields: &[Node<FieldDefinition>],
349) -> Result<(), fmt::Error> {
350    state.write(name)?;
351    if let Some((first, rest)) = implements_interfaces.split_first() {
352        state.write(" implements ")?;
353        state.write(first)?;
354        for name in rest {
355            state.write(" & ")?;
356            state.write(name)?;
357        }
358    }
359    directives.serialize_impl(state)?;
360
361    if !fields.is_empty() {
362        state.write(" ")?;
363        curly_brackets_space_separated(state, fields, |state, field| field.serialize_impl(state))?;
364    }
365    Ok(())
366}
367
368impl InterfaceTypeDefinition {
369    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
370        let Self {
371            description,
372            name,
373            implements_interfaces,
374            directives,
375            fields,
376        } = self;
377        serialize_description(state, description)?;
378        state.write("interface ")?;
379        serialize_object_type_like(state, name, implements_interfaces, directives, fields)
380    }
381}
382
383impl UnionTypeDefinition {
384    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
385        let Self {
386            description,
387            name,
388            directives,
389            members,
390        } = self;
391        serialize_description(state, description)?;
392        state.write("union ")?;
393        serialize_union(state, name, directives, members)
394    }
395}
396
397fn serialize_union(
398    state: &mut State,
399    name: &str,
400    directives: &DirectiveList,
401    members: &[Name],
402) -> fmt::Result {
403    state.write(name)?;
404    directives.serialize_impl(state)?;
405    if let Some((first, rest)) = members.split_first() {
406        state.write(" = ")?;
407        state.write(first)?;
408        for member in rest {
409            state.write(" | ")?;
410            state.write(member)?;
411        }
412    }
413    Ok(())
414}
415
416impl EnumTypeDefinition {
417    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
418        let Self {
419            description,
420            name,
421            directives,
422            values,
423        } = self;
424        serialize_description(state, description)?;
425        state.write("enum ")?;
426        state.write(name)?;
427        directives.serialize_impl(state)?;
428        if !values.is_empty() {
429            state.write(" ")?;
430            curly_brackets_space_separated(state, values, |state, value| {
431                value.serialize_impl(state)
432            })?;
433        }
434        Ok(())
435    }
436}
437
438impl InputObjectTypeDefinition {
439    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
440        let Self {
441            description,
442            name,
443            directives,
444            fields,
445        } = self;
446        serialize_description(state, description)?;
447        state.write("input ")?;
448        state.write(name)?;
449        directives.serialize_impl(state)?;
450        if !fields.is_empty() {
451            state.write(" ")?;
452            curly_brackets_space_separated(state, fields, |state, f| f.serialize_impl(state))?;
453        }
454        Ok(())
455    }
456}
457
458impl SchemaExtension {
459    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
460        let Self {
461            directives,
462            root_operations,
463        } = self;
464        state.write("extend schema")?;
465        directives.serialize_impl(state)?;
466        if !root_operations.is_empty() {
467            state.write(" ")?;
468            curly_brackets_space_separated(state, root_operations, |state, op| {
469                let (operation_type, operation_name) = &**op;
470                display!(state, "{}: {}", operation_type, operation_name)
471            })?;
472        }
473        Ok(())
474    }
475}
476
477impl ScalarTypeExtension {
478    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
479        let Self { name, directives } = self;
480        state.write("extend scalar ")?;
481        state.write(name)?;
482        directives.serialize_impl(state)
483    }
484}
485
486impl ObjectTypeExtension {
487    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
488        let Self {
489            name,
490            implements_interfaces,
491            directives,
492            fields,
493        } = self;
494        state.write("extend type ")?;
495        serialize_object_type_like(state, name, implements_interfaces, directives, fields)
496    }
497}
498
499impl InterfaceTypeExtension {
500    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
501        let Self {
502            name,
503            implements_interfaces,
504            directives,
505            fields,
506        } = self;
507        state.write("extend interface ")?;
508        serialize_object_type_like(state, name, implements_interfaces, directives, fields)
509    }
510}
511
512impl UnionTypeExtension {
513    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
514        let Self {
515            name,
516            directives,
517            members,
518        } = self;
519        state.write("extend union ")?;
520        serialize_union(state, name, directives, members)
521    }
522}
523
524impl EnumTypeExtension {
525    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
526        let Self {
527            name,
528            directives,
529            values,
530        } = self;
531        state.write("extend enum ")?;
532        state.write(name)?;
533        directives.serialize_impl(state)?;
534        if !values.is_empty() {
535            state.write(" ")?;
536            curly_brackets_space_separated(state, values, |state, value| {
537                value.serialize_impl(state)
538            })?;
539        }
540        Ok(())
541    }
542}
543
544impl InputObjectTypeExtension {
545    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
546        let Self {
547            name,
548            directives,
549            fields,
550        } = self;
551        state.write("extend input ")?;
552        state.write(name)?;
553        directives.serialize_impl(state)?;
554        if !fields.is_empty() {
555            state.write(" ")?;
556            curly_brackets_space_separated(state, fields, |state, f| f.serialize_impl(state))?;
557        }
558        Ok(())
559    }
560}
561
562impl DirectiveList {
563    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
564        for dir in self {
565            state.write(" ")?;
566            dir.serialize_impl(state)?;
567        }
568        Ok(())
569    }
570}
571
572impl Directive {
573    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
574        let Self { name, arguments } = self;
575        state.write("@")?;
576        state.write(name)?;
577        serialize_arguments(state, arguments)
578    }
579}
580
581impl VariableDefinition {
582    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
583        let Self {
584            name,
585            ty,
586            default_value,
587            directives,
588        } = self;
589        state.write("$")?;
590        state.write(name)?;
591        state.write(": ")?;
592        display!(state, ty)?;
593        if let Some(value) = default_value {
594            state.write(" = ")?;
595            value.serialize_impl(state)?
596        }
597        directives.serialize_impl(state)
598    }
599}
600
601impl FieldDefinition {
602    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
603        let Self {
604            description,
605            name,
606            arguments,
607            ty,
608            directives,
609        } = self;
610        serialize_description(state, description)?;
611        state.write(name)?;
612        serialize_arguments_definition(state, arguments)?;
613        state.write(": ")?;
614        display!(state, ty)?;
615        directives.serialize_impl(state)
616    }
617}
618
619impl InputValueDefinition {
620    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
621        let Self {
622            description,
623            name,
624            ty,
625            default_value,
626            directives,
627        } = self;
628        serialize_description(state, description)?;
629        state.write(name)?;
630        state.write(": ")?;
631        display!(state, ty)?;
632        if let Some(value) = default_value {
633            state.write(" = ")?;
634            value.serialize_impl(state)?
635        }
636        directives.serialize_impl(state)
637    }
638}
639
640impl EnumValueDefinition {
641    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
642        let Self {
643            description,
644            value,
645            directives,
646        } = self;
647        serialize_description(state, description)?;
648        state.write(value)?;
649        directives.serialize_impl(state)
650    }
651}
652
653impl Selection {
654    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
655        match self {
656            Selection::Field(x) => x.serialize_impl(state),
657            Selection::FragmentSpread(x) => x.serialize_impl(state),
658            Selection::InlineFragment(x) => x.serialize_impl(state),
659        }
660    }
661}
662
663impl Field {
664    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
665        let Self {
666            alias,
667            name,
668            arguments,
669            directives,
670            selection_set,
671        } = self;
672        if let Some(alias) = alias {
673            state.write(alias)?;
674            state.write(": ")?;
675        }
676        state.write(name)?;
677        serialize_arguments(state, arguments)?;
678        directives.serialize_impl(state)?;
679        if !selection_set.is_empty() {
680            state.write(" ")?;
681            curly_brackets_space_separated(state, selection_set, |state, sel| {
682                sel.serialize_impl(state)
683            })?
684        }
685        Ok(())
686    }
687}
688
689impl FragmentSpread {
690    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
691        let Self {
692            fragment_name,
693            directives,
694        } = self;
695        state.write("...")?;
696        state.write(fragment_name)?;
697        directives.serialize_impl(state)
698    }
699}
700
701impl InlineFragment {
702    pub(crate) fn serialize_impl(&self, state: &mut State) -> fmt::Result {
703        let Self {
704            type_condition,
705            directives,
706            selection_set,
707        } = self;
708        if let Some(type_name) = type_condition {
709            state.write("... on ")?;
710            state.write(type_name)?;
711        } else {
712            state.write("...")?;
713        }
714        directives.serialize_impl(state)?;
715        state.write(" ")?;
716        curly_brackets_space_separated(state, selection_set, |state, sel| sel.serialize_impl(state))
717    }
718}
719
720impl Value {
721    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
722        match self {
723            Value::Null => state.write("null"),
724            Value::Boolean(true) => state.write("true"),
725            Value::Boolean(false) => state.write("false"),
726            Value::Enum(name) => state.write(name),
727            Value::String(value) => {
728                let is_description = false;
729                serialize_string_value(state, is_description, value)
730            }
731            Value::Variable(name) => display!(state, "${}", name),
732            Value::Float(value) => display!(state, value),
733            Value::Int(value) => display!(state, value),
734            Value::List(value) => comma_separated(state, "[", "]", value, |state, value| {
735                value.serialize_impl(state)
736            }),
737            Value::Object(value) => {
738                comma_separated(state, "{", "}", value, |state, (name, value)| {
739                    state.write(name)?;
740                    state.write(": ")?;
741                    value.serialize_impl(state)
742                })
743            }
744        }
745    }
746}
747
748impl Argument {
749    fn serialize_impl(&self, state: &mut State) -> fmt::Result {
750        state.write(&self.name)?;
751        state.write(": ")?;
752        self.value.serialize_impl(state)
753    }
754}
755
756fn serialize_arguments(state: &mut State, arguments: &[Node<Argument>]) -> fmt::Result {
757    if !arguments.is_empty() {
758        state.on_single_line(|state| {
759            comma_separated(state, "(", ")", arguments, |state, argument| {
760                argument.serialize_impl(state)
761            })
762        })?
763    }
764    Ok(())
765}
766
767/// Example output: `[a, b, c]` or
768///
769/// ```text
770/// [
771///     a,
772///     b,
773///     c,
774/// ]
775/// ```
776fn comma_separated<T>(
777    state: &mut State,
778    open: &str,
779    close: &str,
780    values: &[T],
781    serialize_one: impl Fn(&mut State, &T) -> fmt::Result,
782) -> fmt::Result {
783    state.write(open)?;
784    if let Some((first, rest)) = values.split_first() {
785        state.indent()?;
786        serialize_one(state, first)?;
787        for value in rest {
788            state.write(",")?;
789            state.new_line_or_space()?;
790            serialize_one(state, value)?;
791        }
792        // Trailing comma
793        if state.newlines_enabled() {
794            state.write(",")?;
795        }
796        state.dedent()?;
797    }
798    state.write(close)
799}
800
801/// Example output: `{ a b c }` or
802///
803/// ```text
804/// {
805///     a
806///     b
807///     c
808/// }
809/// ```
810pub(crate) fn curly_brackets_space_separated<T>(
811    state: &mut State,
812    values: &[T],
813    serialize_one: impl Fn(&mut State, &T) -> fmt::Result,
814) -> fmt::Result {
815    state.write("{")?;
816    if let Some((first, rest)) = values.split_first() {
817        state.indent_or_space()?;
818        serialize_one(state, first)?;
819        for value in rest {
820            state.new_line_or_space()?;
821            serialize_one(state, value)?;
822        }
823        state.dedent_or_space()?;
824    }
825    state.write("}")
826}
827
828fn serialize_string_value(state: &mut State, is_description: bool, mut str: &str) -> fmt::Result {
829    let contains_newline = str.contains('\n');
830    let prefer_block_string = is_description || contains_newline;
831    if state.newlines_enabled() && prefer_block_string && can_be_block_string(str) {
832        return serialize_block_string(state, contains_newline, str);
833    }
834    state.write("\"")?;
835    loop {
836        if let Some(i) = str.find(|c| (c < ' ' && c != '\t') || c == '"' || c == '\\') {
837            let (without_escaping, rest) = str.split_at(i);
838            state.write(without_escaping)?;
839            // All characters that need escaping are in the ASCII range,
840            // and so take a single byte in UTF-8.
841            match rest.as_bytes()[0] {
842                b'\x08' => state.write("\\b")?,
843                b'\n' => state.write("\\n")?,
844                b'\x0C' => state.write("\\f")?,
845                b'\r' => state.write("\\r")?,
846                b'"' => state.write("\\\"")?,
847                b'\\' => state.write("\\\\")?,
848                byte => display!(state, "\\u{:04X}", byte)?,
849            }
850            str = &rest[1..]
851        } else {
852            state.write(str)?;
853            break;
854        }
855    }
856    state.write("\"")
857}
858
859fn serialize_block_string(state: &mut State, contains_newline: bool, str: &str) -> fmt::Result {
860    const TRIPLE_QUOTE: &str = "\"\"\"";
861    const ESCAPED_TRIPLE_QUOTE: &str = "\\\"\"\"";
862    const _: () = assert!(TRIPLE_QUOTE.len() == 3);
863    const _: () = assert!(ESCAPED_TRIPLE_QUOTE.len() == 4);
864
865    fn serialize_line(state: &mut State, mut line: &str) -> Result<(), fmt::Error> {
866        while let Some((before, after)) = line.split_once(TRIPLE_QUOTE) {
867            state.write(before)?;
868            state.write(ESCAPED_TRIPLE_QUOTE)?;
869            line = after;
870        }
871        state.write(line)
872    }
873
874    let multi_line =
875        contains_newline || str.len() > 70 || str.ends_with('"') || str.ends_with('\\');
876
877    state.write(TRIPLE_QUOTE)?;
878    if !multi_line {
879        // """example""""
880        serialize_line(state, str)?
881    } else {
882        // """
883        // example
884        // """
885
886        // `can_be_block_string` excludes \r, so the only remaining line terminator is \n
887        for line in str.split('\n') {
888            if line.is_empty() {
889                // Skip indentation which would be trailing whitespace
890                state.write("\n")?;
891            } else {
892                state.require_new_line()?;
893                serialize_line(state, line)?;
894            }
895        }
896        state.require_new_line()?;
897    }
898    state.write(TRIPLE_QUOTE)
899}
900
901/// Is it possible to create a serialization that, when fed through
902/// [BlockStringValue](https://spec.graphql.org/October2021/#BlockStringValue()),
903/// returns exactly `value`?
904fn can_be_block_string(value: &str) -> bool {
905    // `BlockStringValue` splits its inputs at any `LineTerminator` (\n, \r\n, or \r)
906    // and eventually joins lines but always with \n. So its output can never contain \r
907    if value.contains('\r') {
908        return false;
909    }
910
911    /// <https://spec.graphql.org/October2021/#WhiteSpace>
912    fn trim_start_graphql_whitespace(value: &str) -> &str {
913        value.trim_start_matches([' ', '\t'])
914    }
915
916    // With the above, \n is the only remaining LineTerminator
917    let mut lines = value.split('\n');
918    if lines
919        .next()
920        .is_some_and(|first| trim_start_graphql_whitespace(first).is_empty())
921        || lines
922            .next_back()
923            .is_some_and(|last| trim_start_graphql_whitespace(last).is_empty())
924    {
925        // Leading or trailing whitespace-only line would be trimmed by `BlockStringValue`
926        return false;
927    }
928
929    let common_indent = {
930        let lines = value.split('\n');
931        let each_line_indent_utf8_len = lines.filter_map(|line| {
932            let after_indent = trim_start_graphql_whitespace(line);
933            if !after_indent.is_empty() {
934                Some(line.len() - after_indent.len())
935            } else {
936                None // skip whitespace-only lines
937            }
938        });
939        each_line_indent_utf8_len.min().unwrap_or(0)
940    };
941    // If there is common indent `BlockStringValue` would remove it
942    // and incorrectly round-trip to a different value.
943    common_indent == 0
944}
945
946fn serialize_description(state: &mut State, description: &Option<Node<str>>) -> fmt::Result {
947    if let Some(description) = description {
948        let is_description = true;
949        serialize_string_value(state, is_description, description)?;
950        state.new_line_or_space()?;
951    }
952    Ok(())
953}
954
955impl fmt::Display for Type {
956    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
957        match self {
958            Type::Named(name) => std::write!(f, "{name}"),
959            Type::NonNullNamed(name) => std::write!(f, "{name}!"),
960            Type::List(inner) => std::write!(f, "[{inner}]"),
961            Type::NonNullList(inner) => std::write!(f, "[{inner}]!"),
962        }
963    }
964}
965
966impl fmt::Display for OperationType {
967    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
968        self.name().fmt(f)
969    }
970}
971
972impl fmt::Display for DirectiveLocation {
973    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
974        self.name().fmt(f)
975    }
976}
977
978macro_rules! impl_display {
979    ($($ty: path)+) => {
980        $(
981            /// Serialize to GraphQL syntax with the default configuration
982            impl Display for $ty {
983                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
984                    self.serialize().fmt(f)
985                }
986            }
987
988            /// Serialize to GraphQL syntax
989            impl Display for Serialize<'_, $ty> {
990                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
991                    let mut state = State {
992                        config: self.config.clone(),
993                        indent_level: self.config.initial_indent_level,
994                        output: f,
995                        output_empty: true,
996                    };
997                    // Indent the first line.
998                    // Subsequent lines will be indented when writing a line break.
999                    if let Some(prefix) = state.config.indent_prefix {
1000                        for _ in 0..state.indent_level {
1001                            state.write(prefix)?;
1002                        }
1003                    }
1004                    self.node.serialize_impl(&mut state)
1005                }
1006            }
1007        )+
1008    }
1009}
1010
1011impl_display! {
1012    Document
1013    Definition
1014    OperationDefinition
1015    FragmentDefinition
1016    DirectiveDefinition
1017    SchemaDefinition
1018    ScalarTypeDefinition
1019    ObjectTypeDefinition
1020    InterfaceTypeDefinition
1021    UnionTypeDefinition
1022    EnumTypeDefinition
1023    InputObjectTypeDefinition
1024    SchemaExtension
1025    ScalarTypeExtension
1026    ObjectTypeExtension
1027    InterfaceTypeExtension
1028    UnionTypeExtension
1029    EnumTypeExtension
1030    InputObjectTypeExtension
1031    DirectiveList
1032    Directive
1033    VariableDefinition
1034    FieldDefinition
1035    InputValueDefinition
1036    EnumValueDefinition
1037    Selection
1038    Field
1039    FragmentSpread
1040    InlineFragment
1041    Value
1042    crate::Schema
1043    crate::ExecutableDocument
1044    schema::DirectiveList
1045    schema::ExtendedType
1046    schema::ScalarType
1047    schema::ObjectType
1048    schema::InterfaceType
1049    schema::EnumType
1050    schema::UnionType
1051    schema::InputObjectType
1052    executable::Operation
1053    executable::Fragment
1054    executable::SelectionSet
1055    executable::Selection
1056    executable::Field
1057    executable::InlineFragment
1058    executable::FragmentSpread
1059    executable::FieldSet
1060}