Skip to main content

graphql_tools/parser/schema/
format.rs

1use std::fmt;
2
3use crate::parser::common::Text;
4use crate::parser::format::{format_directives, Displayable, Formatter, Style};
5
6use super::ast::*;
7
8impl<'a, T> Document<'a, T>
9where
10    T: Text<'a>,
11{
12    /// Format a document according to style
13    pub fn format(&self, style: &Style) -> String {
14        let mut formatter = Formatter::new(style);
15        self.display(&mut formatter);
16        formatter.into_string()
17    }
18}
19
20impl<'a, T> Definition<'a, T>
21where
22    T: Text<'a>,
23{
24    /// Formats the definition onto the end of `buf`, exactly like `Document::format` would
25    /// format it as one of the document's definitions
26    pub fn format_into(&self, style: &Style, buf: &mut String) {
27        let mut formatter = Formatter::with_buf(style, std::mem::take(buf));
28        self.display(&mut formatter);
29        *buf = formatter.into_string();
30    }
31}
32
33fn to_string<T: Displayable>(v: &T) -> String {
34    let style = Style::default();
35    let mut formatter = Formatter::new(&style);
36    v.display(&mut formatter);
37    formatter.into_string()
38}
39
40fn description(description: &Option<String>, f: &mut Formatter) {
41    if let Some(ref descr) = *description {
42        f.indent();
43        f.write_quoted(descr.as_ref());
44        f.endline();
45    }
46}
47
48impl<'a, T> Displayable for Document<'a, T>
49where
50    T: Text<'a>,
51{
52    fn display(&self, f: &mut Formatter) {
53        for item in &self.definitions {
54            item.display(f);
55        }
56    }
57}
58
59impl<'a, T> Displayable for Definition<'a, T>
60where
61    T: Text<'a>,
62{
63    fn display(&self, f: &mut Formatter) {
64        f.margin();
65        match *self {
66            Definition::SchemaDefinition(ref s) => s.display(f),
67            Definition::TypeDefinition(ref t) => t.display(f),
68            Definition::TypeExtension(ref e) => e.display(f),
69            Definition::DirectiveDefinition(ref d) => d.display(f),
70        }
71    }
72}
73
74impl<'a, T> Displayable for SchemaDefinition<'a, T>
75where
76    T: Text<'a>,
77{
78    fn display(&self, f: &mut Formatter) {
79        f.indent();
80        f.write("schema");
81        format_directives(&self.directives, f);
82        f.write(" ");
83        f.start_block();
84        if let Some(ref q) = self.query {
85            f.indent();
86            f.write("query: ");
87            f.write(q.as_ref());
88            f.endline();
89        }
90        if let Some(ref m) = self.mutation {
91            f.indent();
92            f.write("mutation: ");
93            f.write(m.as_ref());
94            f.endline();
95        }
96        if let Some(ref s) = self.subscription {
97            f.indent();
98            f.write("subscription: ");
99            f.write(s.as_ref());
100            f.endline();
101        }
102        f.end_block();
103    }
104}
105
106impl<'a, T> Displayable for TypeDefinition<'a, T>
107where
108    T: Text<'a>,
109{
110    fn display(&self, f: &mut Formatter) {
111        match *self {
112            TypeDefinition::Scalar(ref s) => s.display(f),
113            TypeDefinition::Object(ref o) => o.display(f),
114            TypeDefinition::Interface(ref i) => i.display(f),
115            TypeDefinition::Union(ref u) => u.display(f),
116            TypeDefinition::Enum(ref e) => e.display(f),
117            TypeDefinition::InputObject(ref i) => i.display(f),
118        }
119    }
120}
121
122impl<'a, T> Displayable for ScalarType<'a, T>
123where
124    T: Text<'a>,
125{
126    fn display(&self, f: &mut Formatter) {
127        description(&self.description, f);
128        f.indent();
129        f.write("scalar ");
130        f.write(self.name.as_ref());
131        format_directives(&self.directives, f);
132        f.endline();
133    }
134}
135
136impl<'a, T> Displayable for ScalarTypeExtension<'a, T>
137where
138    T: Text<'a>,
139{
140    fn display(&self, f: &mut Formatter) {
141        f.indent();
142        f.write("extend scalar ");
143        f.write(self.name.as_ref());
144        format_directives(&self.directives, f);
145        f.endline();
146    }
147}
148
149fn format_fields<'a, T>(fields: &[Field<'a, T>], f: &mut Formatter)
150where
151    T: Text<'a>,
152{
153    if !fields.is_empty() {
154        f.write(" ");
155        f.start_block();
156        for fld in fields {
157            fld.display(f);
158        }
159        f.end_block();
160    } else {
161        f.endline();
162    }
163}
164
165impl<'a, T> Displayable for ObjectType<'a, T>
166where
167    T: Text<'a>,
168{
169    fn display(&self, f: &mut Formatter) {
170        description(&self.description, f);
171        f.indent();
172        f.write("type ");
173        f.write(self.name.as_ref());
174        if !self.implements_interfaces.is_empty() {
175            f.write(" implements ");
176            f.write(self.implements_interfaces[0].as_ref());
177            for name in &self.implements_interfaces[1..] {
178                f.write(" & ");
179                f.write(name.as_ref());
180            }
181        }
182        format_directives(&self.directives, f);
183        format_fields(&self.fields, f);
184    }
185}
186
187impl<'a, T> Displayable for ObjectTypeExtension<'a, T>
188where
189    T: Text<'a>,
190{
191    fn display(&self, f: &mut Formatter) {
192        f.indent();
193        f.write("extend type ");
194        f.write(self.name.as_ref());
195        if !self.implements_interfaces.is_empty() {
196            f.write(" implements ");
197            f.write(self.implements_interfaces[0].as_ref());
198            for name in &self.implements_interfaces[1..] {
199                f.write(" & ");
200                f.write(name.as_ref());
201            }
202        }
203        format_directives(&self.directives, f);
204        format_fields(&self.fields, f);
205    }
206}
207
208impl<'a, T> Displayable for InputValue<'a, T>
209where
210    T: Text<'a>,
211{
212    fn display(&self, f: &mut Formatter) {
213        if let Some(ref descr) = self.description {
214            f.write_quoted(descr.as_ref());
215            f.write(" ");
216        }
217        f.write(self.name.as_ref());
218        f.write(": ");
219        self.value_type.display(f);
220        if let Some(ref def) = self.default_value {
221            f.write(" = ");
222            def.display(f);
223        }
224        format_directives(&self.directives, f);
225    }
226}
227
228fn format_arguments<'a, T>(arguments: &[InputValue<'a, T>], f: &mut Formatter)
229where
230    T: Text<'a>,
231{
232    if !arguments.is_empty() {
233        f.write("(");
234        arguments[0].display(f);
235        for arg in &arguments[1..] {
236            f.write(", ");
237            arg.display(f);
238        }
239        f.write(")");
240    }
241}
242
243impl<'a, T> Displayable for Field<'a, T>
244where
245    T: Text<'a>,
246{
247    fn display(&self, f: &mut Formatter) {
248        description(&self.description, f);
249        f.indent();
250        f.write(self.name.as_ref());
251        format_arguments(&self.arguments, f);
252        f.write(": ");
253        self.field_type.display(f);
254        format_directives(&self.directives, f);
255        f.endline();
256    }
257}
258
259impl<'a, T> Displayable for InterfaceType<'a, T>
260where
261    T: Text<'a>,
262{
263    fn display(&self, f: &mut Formatter) {
264        description(&self.description, f);
265        f.indent();
266        f.write("interface ");
267        f.write(self.name.as_ref());
268        if !self.implements_interfaces.is_empty() {
269            f.write(" implements ");
270            f.write(self.implements_interfaces[0].as_ref());
271            for name in &self.implements_interfaces[1..] {
272                f.write(" & ");
273                f.write(name.as_ref());
274            }
275        }
276        format_directives(&self.directives, f);
277        format_fields(&self.fields, f);
278    }
279}
280
281impl<'a, T> Displayable for InterfaceTypeExtension<'a, T>
282where
283    T: Text<'a>,
284{
285    fn display(&self, f: &mut Formatter) {
286        f.indent();
287        f.write("extend interface ");
288        f.write(self.name.as_ref());
289        if !self.implements_interfaces.is_empty() {
290            f.write(" implements ");
291            f.write(self.implements_interfaces[0].as_ref());
292            for name in &self.implements_interfaces[1..] {
293                f.write(" & ");
294                f.write(name.as_ref());
295            }
296        }
297        format_directives(&self.directives, f);
298        format_fields(&self.fields, f);
299    }
300}
301
302impl<'a, T> Displayable for UnionType<'a, T>
303where
304    T: Text<'a>,
305{
306    fn display(&self, f: &mut Formatter) {
307        description(&self.description, f);
308        f.indent();
309        f.write("union ");
310        f.write(self.name.as_ref());
311        format_directives(&self.directives, f);
312        if !self.types.is_empty() {
313            f.write(" = ");
314            f.write(self.types[0].as_ref());
315            for typ in &self.types[1..] {
316                f.write(" | ");
317                f.write(typ.as_ref());
318            }
319        }
320        f.endline();
321    }
322}
323
324impl<'a, T> Displayable for UnionTypeExtension<'a, T>
325where
326    T: Text<'a>,
327{
328    fn display(&self, f: &mut Formatter) {
329        f.indent();
330        f.write("extend union ");
331        f.write(self.name.as_ref());
332        format_directives(&self.directives, f);
333        if !self.types.is_empty() {
334            f.write(" = ");
335            f.write(self.types[0].as_ref());
336            for typ in &self.types[1..] {
337                f.write(" | ");
338                f.write(typ.as_ref());
339            }
340        }
341        f.endline();
342    }
343}
344
345impl<'a, T> Displayable for EnumType<'a, T>
346where
347    T: Text<'a>,
348{
349    fn display(&self, f: &mut Formatter) {
350        description(&self.description, f);
351        f.indent();
352        f.write("enum ");
353        f.write(self.name.as_ref());
354        format_directives(&self.directives, f);
355        if !self.values.is_empty() {
356            f.write(" ");
357            f.start_block();
358            for val in &self.values {
359                f.indent();
360                if let Some(ref descr) = val.description {
361                    f.write_quoted(descr.as_ref());
362                    f.write(" ");
363                }
364                f.write(val.name.as_ref());
365                format_directives(&val.directives, f);
366                f.endline();
367            }
368            f.end_block();
369        } else {
370            f.endline();
371        }
372    }
373}
374
375impl<'a, T> Displayable for EnumTypeExtension<'a, T>
376where
377    T: Text<'a>,
378{
379    fn display(&self, f: &mut Formatter) {
380        f.indent();
381        f.write("extend enum ");
382        f.write(self.name.as_ref());
383        format_directives(&self.directives, f);
384        if !self.values.is_empty() {
385            f.write(" ");
386            f.start_block();
387            for val in &self.values {
388                f.indent();
389                if let Some(ref descr) = val.description {
390                    f.write_quoted(descr.as_ref());
391                    f.write(" ");
392                }
393                f.write(val.name.as_ref());
394                format_directives(&val.directives, f);
395                f.endline();
396            }
397            f.end_block();
398        } else {
399            f.endline();
400        }
401    }
402}
403
404fn format_inputs<'a, T>(fields: &[InputValue<'a, T>], f: &mut Formatter)
405where
406    T: Text<'a>,
407{
408    if !fields.is_empty() {
409        f.write(" ");
410        f.start_block();
411        for fld in fields {
412            f.indent();
413            fld.display(f);
414            f.endline();
415        }
416        f.end_block();
417    } else {
418        f.endline();
419    }
420}
421
422impl<'a, T> Displayable for InputObjectType<'a, T>
423where
424    T: Text<'a>,
425{
426    fn display(&self, f: &mut Formatter) {
427        description(&self.description, f);
428        f.indent();
429        f.write("input ");
430        f.write(self.name.as_ref());
431        format_directives(&self.directives, f);
432        format_inputs(&self.fields, f);
433    }
434}
435
436impl<'a, T> Displayable for InputObjectTypeExtension<'a, T>
437where
438    T: Text<'a>,
439{
440    fn display(&self, f: &mut Formatter) {
441        f.indent();
442        f.write("extend input ");
443        f.write(self.name.as_ref());
444        format_directives(&self.directives, f);
445        format_inputs(&self.fields, f);
446    }
447}
448
449impl<'a, T> Displayable for TypeExtension<'a, T>
450where
451    T: Text<'a>,
452{
453    fn display(&self, f: &mut Formatter) {
454        match *self {
455            TypeExtension::Scalar(ref s) => s.display(f),
456            TypeExtension::Object(ref o) => o.display(f),
457            TypeExtension::Interface(ref i) => i.display(f),
458            TypeExtension::Union(ref u) => u.display(f),
459            TypeExtension::Enum(ref e) => e.display(f),
460            TypeExtension::InputObject(ref i) => i.display(f),
461        }
462    }
463}
464
465impl<'a, T> Displayable for DirectiveDefinition<'a, T>
466where
467    T: Text<'a>,
468{
469    fn display(&self, f: &mut Formatter) {
470        description(&self.description, f);
471        f.indent();
472        f.write("directive @");
473        f.write(self.name.as_ref());
474        format_arguments(&self.arguments, f);
475        if self.repeatable {
476            f.write(" repeatable");
477        }
478        if !self.locations.is_empty() {
479            f.write(" on ");
480            let mut first = true;
481            for loc in &self.locations {
482                if first {
483                    first = false;
484                } else {
485                    f.write(" | ");
486                }
487                f.write(loc.as_str());
488            }
489        }
490        f.endline();
491    }
492}
493
494impl_display!(
495    'a
496    Document,
497    Definition,
498    SchemaDefinition,
499    TypeDefinition,
500    TypeExtension,
501    ScalarType,
502    ScalarTypeExtension,
503    ObjectType,
504    ObjectTypeExtension,
505    Field,
506    InputValue,
507    InterfaceType,
508    InterfaceTypeExtension,
509    UnionType,
510    UnionTypeExtension,
511    EnumType,
512    EnumTypeExtension,
513    InputObjectType,
514    InputObjectTypeExtension,
515    DirectiveDefinition,
516);