1use super::ast::*;
2use std::{fmt, fmt::Write};
3
4pub trait PrintNode {
14 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result;
19
20 fn print(&self) -> String {
25 let mut buf = String::new();
26 match self.write_to_buffer(0, &mut buf) {
27 Ok(()) => buf,
28 _ => "".to_string(),
29 }
30 }
31}
32
33impl fmt::Display for dyn PrintNode {
34 #[inline]
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 self.write_to_buffer(0, f)
37 }
38}
39
40impl<'a> PrintNode for NamedType<'a> {
41 #[inline]
42 fn write_to_buffer(&self, _level: usize, buffer: &mut dyn Write) -> fmt::Result {
43 buffer.write_str(self.name)
44 }
45}
46
47impl<'a> PrintNode for Variable<'a> {
48 #[inline]
49 fn write_to_buffer(&self, _level: usize, buffer: &mut dyn Write) -> fmt::Result {
50 write!(buffer, "${}", self.name)
51 }
52}
53
54impl PrintNode for BooleanValue {
55 #[inline]
56 fn write_to_buffer(&self, _level: usize, buffer: &mut dyn Write) -> fmt::Result {
57 match self.value {
58 true => buffer.write_str("true"),
59 false => buffer.write_str("false"),
60 }
61 }
62}
63
64impl<'a> PrintNode for EnumValue<'a> {
65 #[inline]
66 fn write_to_buffer(&self, _level: usize, buffer: &mut dyn Write) -> fmt::Result {
67 buffer.write_str(self.value)
68 }
69}
70
71impl<'a> PrintNode for FloatValue<'a> {
72 #[inline]
73 fn write_to_buffer(&self, _level: usize, buffer: &mut dyn Write) -> fmt::Result {
74 buffer.write_str(self.value)
75 }
76}
77
78impl<'a> PrintNode for IntValue<'a> {
79 #[inline]
80 fn write_to_buffer(&self, _level: usize, buffer: &mut dyn Write) -> fmt::Result {
81 buffer.write_str(self.value)
82 }
83}
84
85impl<'a> PrintNode for StringValue<'a> {
86 #[inline]
87 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
88 use lexical_core::*;
89 let mut buf = [b'0'; u32::FORMATTED_SIZE];
90
91 if !self.is_block() {
93 buffer.write_char('"')?;
94 for c in self.value.chars() {
95 match c {
96 '\r' => buffer.write_str(r"\r")?,
97 '\n' => buffer.write_str(r"\n")?,
98 '\t' => buffer.write_str(r"\t")?,
99 '"' => buffer.write_str("\\\"")?,
100 '\\' => buffer.write_str(r"\\")?,
101 '\u{0020}'..='\u{FFFF}' => buffer.write_char(c)?,
102 _ => unsafe {
103 const FORMAT: u128 = NumberFormatBuilder::hexadecimal();
104 const OPTIONS: WriteIntegerOptions = WriteIntegerOptions::new();
105 let buf =
106 write_with_options_unchecked::<_, FORMAT>(c as u32, &mut buf, &OPTIONS);
107 write!(buffer, "\\u{:0>4}", std::str::from_utf8_unchecked(buf))?;
108 },
109 };
110 }
111 buffer.write_char('"')
112 } else {
113 buffer.write_str("\"\"\"\n")?;
114 for line in self.value.lines() {
115 if !line.trim().is_empty() {
116 write_indent(level, buffer)?;
117 buffer.write_str(&line.replace(r#"""""#, r#"\""""#))?;
118 }
119 buffer.write_char('\n')?;
120 }
121 write_indent(level, buffer)?;
122 buffer.write_str("\"\"\"")
123 }
124 }
125}
126
127impl<'a> PrintNode for Value<'a> {
128 #[inline]
129 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
130 match self {
131 Value::Boolean(value) => value.write_to_buffer(level, buffer),
132 Value::Enum(value) => value.write_to_buffer(level, buffer),
133 Value::Float(value) => value.write_to_buffer(level, buffer),
134 Value::Int(value) => value.write_to_buffer(level, buffer),
135 Value::String(value) => value.write_to_buffer(level, buffer),
136 Value::Variable(value) => value.write_to_buffer(level, buffer),
137 Value::Object(value) => value.write_to_buffer(level, buffer),
138 Value::List(value) => value.write_to_buffer(level, buffer),
139 Value::Null => buffer.write_str("null"),
140 }
141 }
142}
143
144impl<'a> PrintNode for ObjectField<'a> {
145 #[inline]
146 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
147 write!(buffer, "{}: ", self.name)?;
148 self.value.write_to_buffer(level, buffer)
149 }
150}
151
152impl<'a> PrintNode for ObjectValue<'a> {
153 #[inline]
154 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
155 buffer.write_str("{")?;
156 let mut first = true;
157 for field in self.children.iter() {
158 if first {
159 first = false;
160 } else {
161 buffer.write_str(", ")?;
162 }
163 field.write_to_buffer(level, buffer)?;
164 }
165 buffer.write_str("}")
166 }
167}
168
169impl<'a> PrintNode for ListValue<'a> {
170 #[inline]
171 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
172 buffer.write_str("[")?;
173 let mut first = true;
174 for field in self.children.iter() {
175 if first {
176 first = false;
177 } else {
178 buffer.write_str(", ")?;
179 }
180 field.write_to_buffer(level, buffer)?;
181 }
182 buffer.write_str("]")
183 }
184}
185
186impl<'a> PrintNode for Argument<'a> {
187 #[inline]
188 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
189 write!(buffer, "{}: ", self.name)?;
190 self.value.write_to_buffer(level, buffer)
191 }
192}
193
194impl<'a> PrintNode for Arguments<'a> {
195 #[inline]
196 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
197 if !self.is_empty() {
198 buffer.write_str("(")?;
199 let mut first = true;
200 for argument in self.children.iter() {
201 if first {
202 first = false;
203 } else {
204 buffer.write_str(", ")?;
205 }
206 argument.write_to_buffer(level, buffer)?;
207 }
208 buffer.write_str(")")
209 } else {
210 Ok(())
211 }
212 }
213}
214
215impl<'a> PrintNode for Directive<'a> {
216 #[inline]
217 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
218 write!(buffer, "@{}", self.name)?;
219 self.arguments.write_to_buffer(level, buffer)
220 }
221}
222
223impl<'a> PrintNode for Directives<'a> {
224 #[inline]
225 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
226 for directive in self.children.iter() {
227 buffer.write_str(" ")?;
228 directive.write_to_buffer(level, buffer)?;
229 }
230 Ok(())
231 }
232}
233
234impl<'a> PrintNode for SelectionSet<'a> {
235 #[inline]
236 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
237 if !self.is_empty() {
238 let level = level + 1;
239 buffer.write_str("{")?;
240 for selection in self.selections.iter() {
241 buffer.write_char('\n')?;
242 write_indent(level, buffer)?;
243 match selection {
244 Selection::Field(field) => field.write_to_buffer(level, buffer)?,
245 Selection::FragmentSpread(spread) => spread.write_to_buffer(level, buffer)?,
246 Selection::InlineFragment(inline) => inline.write_to_buffer(level, buffer)?,
247 };
248 }
249 buffer.write_char('\n')?;
250 write_indent(level - 1, buffer)?;
251 buffer.write_char('}')
252 } else {
253 Ok(())
254 }
255 }
256}
257
258impl<'a> PrintNode for Field<'a> {
259 #[inline]
260 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
261 if let Some(alias) = self.alias {
262 write!(buffer, "{}: {}", alias, self.name)?;
263 } else {
264 buffer.write_str(self.name)?;
265 };
266 self.arguments.write_to_buffer(level, buffer)?;
267 self.directives.write_to_buffer(level, buffer)?;
268 if !self.selection_set.is_empty() {
269 buffer.write_str(" ")?;
270 };
271 self.selection_set.write_to_buffer(level, buffer)
272 }
273}
274
275impl<'a> PrintNode for FragmentSpread<'a> {
276 #[inline]
277 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
278 buffer.write_str("...")?;
279 self.name.write_to_buffer(level, buffer)?;
280 self.directives.write_to_buffer(level, buffer)
281 }
282}
283
284impl<'a> PrintNode for InlineFragment<'a> {
285 #[inline]
286 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
287 buffer.write_str("...")?;
288 if let Some(name) = &self.type_condition {
289 buffer.write_str(" on ")?;
290 name.write_to_buffer(level, buffer)?;
291 };
292 self.directives.write_to_buffer(level, buffer)?;
293 buffer.write_str(" ")?;
294 self.selection_set.write_to_buffer(level, buffer)
295 }
296}
297
298impl<'a> PrintNode for Type<'a> {
299 #[inline]
300 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
301 match self {
302 Type::NamedType(name) => name.write_to_buffer(level, buffer),
303 Type::ListType(inner) => {
304 buffer.write_str("[")?;
305 inner.write_to_buffer(level, buffer)?;
306 buffer.write_str("]")
307 }
308 Type::NonNullType(inner) => {
309 inner.write_to_buffer(level, buffer)?;
310 buffer.write_str("!")
311 }
312 }
313 }
314}
315
316impl<'a> PrintNode for VariableDefinition<'a> {
317 #[inline]
318 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
319 self.variable.write_to_buffer(level, buffer)?;
320 buffer.write_str(": ")?;
321 self.of_type.write_to_buffer(level, buffer)?;
322 if self.default_value != Value::Null {
323 buffer.write_str(" = ")?;
324 self.default_value.write_to_buffer(level, buffer)?;
325 }
326 self.directives.write_to_buffer(level, buffer)
327 }
328}
329
330impl<'a> PrintNode for VariableDefinitions<'a> {
331 #[inline]
332 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
333 if !self.is_empty() {
334 buffer.write_str("(")?;
335 let mut first = true;
336 for var_definition in self.children.iter() {
337 if first {
338 first = false;
339 } else {
340 buffer.write_str(", ")?;
341 }
342 var_definition.write_to_buffer(level, buffer)?;
343 }
344 buffer.write_str(")")
345 } else {
346 Ok(())
347 }
348 }
349}
350
351impl<'a> PrintNode for FragmentDefinition<'a> {
352 #[inline]
353 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
354 buffer.write_str("fragment ")?;
355 self.name.write_to_buffer(level, buffer)?;
356 buffer.write_str(" on ")?;
357 self.type_condition.write_to_buffer(level, buffer)?;
358 self.directives.write_to_buffer(level, buffer)?;
359 buffer.write_str(" ")?;
360 self.selection_set.write_to_buffer(level, buffer)
361 }
362}
363
364impl<'a> PrintNode for OperationDefinition<'a> {
365 #[inline]
366 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
367 if self.operation == OperationKind::Query
368 && self.name.is_none()
369 && self.variable_definitions.is_empty()
370 && self.directives.is_empty()
371 {
372 self.selection_set.write_to_buffer(level, buffer)
373 } else {
374 match self.operation {
375 OperationKind::Query => buffer.write_str("query")?,
376 OperationKind::Mutation => buffer.write_str("mutation")?,
377 OperationKind::Subscription => buffer.write_str("subscription")?,
378 };
379 if let Some(name) = &self.name {
380 buffer.write_str(" ")?;
381 name.write_to_buffer(level, buffer)?;
382 };
383 if self.name.is_none() && !self.variable_definitions.is_empty() {
384 buffer.write_str(" ")?;
385 }
386 self.variable_definitions.write_to_buffer(level, buffer)?;
387 self.directives.write_to_buffer(level, buffer)?;
388 buffer.write_str(" ")?;
389 self.selection_set.write_to_buffer(level, buffer)
390 }
391 }
392}
393
394impl<'a> PrintNode for Definition<'a> {
395 #[inline]
396 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
397 match self {
398 Definition::Operation(operation) => operation.write_to_buffer(level, buffer),
399 Definition::Fragment(fragment) => fragment.write_to_buffer(level, buffer),
400 }
401 }
402}
403
404impl<'a> PrintNode for Document<'a> {
405 #[inline]
406 fn write_to_buffer(&self, level: usize, buffer: &mut dyn Write) -> fmt::Result {
407 let mut first = true;
408 for definition in self.definitions.iter() {
409 if first {
410 first = false;
411 } else {
412 buffer.write_str("\n\n")?;
413 }
414 definition.write_to_buffer(level, buffer)?;
415 }
416 Ok(())
417 }
418
419 #[inline]
420 fn print(&self) -> String {
421 let mut buf = String::with_capacity(self.size_hint);
422 match self.write_to_buffer(0, &mut buf) {
423 Ok(()) => buf,
424 _ => "".to_string(),
425 }
426 }
427}
428
429#[inline(always)]
430fn write_indent(level: usize, buffer: &mut dyn Write) -> fmt::Result {
431 for _ in 0..level {
432 buffer.write_str(" ")?
433 }
434 Ok(())
435}
436
437#[cfg(test)]
438mod tests {
439 use super::super::*;
440
441 #[test]
442 fn values() {
443 let ctx = ASTContext::new();
444 let ast = Value::parse(&ctx, "{ a: true, b: [1, 2] }");
445 assert_eq!(ast.unwrap().print(), "{a: true, b: [1, 2]}");
446 let ast = Value::parse(&ctx, "123.23");
447 assert_eq!(ast.unwrap().print(), "123.23");
448 let ast = Value::parse(&ctx, "123.23e20");
449 assert_eq!(ast.unwrap().print(), "123.23e20");
450 }
451
452 #[test]
453 fn arguments() {
454 let ctx = ASTContext::new();
455 let ast = Arguments::parse(&ctx, "()");
456 assert_eq!(ast.unwrap().print(), "");
457 let ast = Arguments::parse(&ctx, "(a:1)");
458 assert_eq!(ast.unwrap().print(), "(a: 1)");
459 let ast = Arguments::parse(&ctx, "(a:1 b:2)");
460 assert_eq!(ast.unwrap().print(), "(a: 1, b: 2)");
461 }
462
463 #[test]
464 fn directives() {
465 let ctx = ASTContext::new();
466 let ast = Directives::parse(&ctx, "@skip(if: true)");
467 assert_eq!(ast.unwrap().print(), " @skip(if: true)");
468 let ast = Directives::parse(&ctx, "@skip(if: true) @include(if: false)");
469 assert_eq!(ast.unwrap().print(), " @skip(if: true) @include(if: false)");
470 }
471
472 #[test]
473 fn field() {
474 let ctx = ASTContext::new();
475 let ast = Field::parse(&ctx, "field { child }");
476 assert_eq!(ast.unwrap().print(), "field {\n child\n}");
477 let ast = Field::parse(&ctx, "field { child { child } }");
478 assert_eq!(
479 ast.unwrap().print(),
480 "field {\n child {\n child\n }\n}"
481 );
482 let ast = Field::parse(&ctx, "alias : field");
483 assert_eq!(ast.unwrap().print(), "alias: field");
484 let ast = Field::parse(&ctx, "field: field");
485 assert_eq!(ast.unwrap().print(), "field: field");
486 let ast = Field::parse(&ctx, "field (test: true)");
487 assert_eq!(ast.unwrap().print(), "field(test: true)");
488 let ast = Field::parse(&ctx, "field (test: true) @test");
489 assert_eq!(ast.unwrap().print(), "field(test: true) @test");
490 }
491
492 #[test]
493 fn fragment_spread() {
494 let ctx = ASTContext::new();
495 let ast = FragmentSpread::parse(&ctx, "...Type");
496 assert_eq!(ast.unwrap().print(), "...Type");
497 let ast = FragmentSpread::parse(&ctx, "...Type @test");
498 assert_eq!(ast.unwrap().print(), "...Type @test");
499 }
500
501 #[test]
502 fn inline_fragment() {
503 let ctx = ASTContext::new();
504 let ast = InlineFragment::parse(&ctx, "... on Type { field }");
505 assert_eq!(ast.unwrap().print(), "... on Type {\n field\n}");
506 let ast = InlineFragment::parse(&ctx, "... on Type @test{ field }");
507 assert_eq!(ast.unwrap().print(), "... on Type @test {\n field\n}");
508 let ast = InlineFragment::parse(&ctx, "...@test { field }");
509 assert_eq!(ast.unwrap().print(), "... @test {\n field\n}");
510 }
511
512 #[test]
513 fn _type() {
514 let ctx = ASTContext::new();
515 let ast = Type::parse(&ctx, "[Type]");
516 assert_eq!(ast.unwrap().print(), "[Type]");
517 let ast = Type::parse(&ctx, "[Type !] !");
518 assert_eq!(ast.unwrap().print(), "[Type!]!");
519 let ast = Type::parse(&ctx, "Type!");
520 assert_eq!(ast.unwrap().print(), "Type!");
521 }
522
523 #[test]
524 fn variable_definitions() {
525 let ctx = ASTContext::new();
526 let ast = VariableDefinitions::parse(&ctx, "($x : Int)");
527 assert_eq!(ast.unwrap().print(), "($x: Int)");
528 let ast = VariableDefinitions::parse(&ctx, "($x : Int = 1)");
529 assert_eq!(ast.unwrap().print(), "($x: Int = 1)");
530 let ast = VariableDefinitions::parse(&ctx, "($x : Int = 1, $y: Bool)");
531 assert_eq!(ast.unwrap().print(), "($x: Int = 1, $y: Bool)");
532 }
533
534 #[test]
535 fn strings() {
536 let ctx = ASTContext::new();
537 let ast = Value::parse(&ctx, "\"\\u0001\"");
538 assert_eq!(ast.unwrap().print(), "\"\\u0001\"");
539 let ast = Value::parse(&ctx, "\"\\u0019\"");
540 assert_eq!(ast.unwrap().print(), "\"\\u0019\"");
541 let ast = Value::parse(&ctx, "\"\0\"");
542 assert_eq!(ast.unwrap().print(), "\"\\u0000\"");
543 }
544
545 #[test]
546 fn block_strings() {
547 let ctx = ASTContext::new();
548 let ast = Value::parse(
549 &ctx,
550 r#"
551 """
552 this
553 is
554 doc
555 """
556 "#,
557 );
558 assert_eq!(ast.unwrap().print(), "\"\"\"\nthis\n is\ndoc\n\"\"\"");
559
560 let ast = Value::parse(
561 &ctx,
562 r#"
563 """this
564 is
565 doc"""
566 "#,
567 );
568 assert_eq!(ast.unwrap().print(), "\"\"\"\nthis\n is\ndoc\n\"\"\"");
569
570 let ast = Value::parse(
571 &ctx,
572 r#"
573 """
574 this
575 is
576 doc
577 """
578 "#,
579 );
580 assert_eq!(ast.unwrap().print(), "\"\"\"\n this\n is\n doc\n\"\"\"");
581 }
582
583 #[test]
584 fn fragment_definitions() {
585 let ctx = ASTContext::new();
586 let ast = FragmentDefinition::parse(
587 &ctx,
588 r#"
589 fragment Test on Type {
590 field
591 }
592 "#,
593 );
594 assert_eq!(ast.unwrap().print(), "fragment Test on Type {\n field\n}");
595
596 let ast = FragmentDefinition::parse(
597 &ctx,
598 r#"
599 fragment Test on Type @test {
600 field
601 }
602 "#,
603 );
604 assert_eq!(
605 ast.unwrap().print(),
606 "fragment Test on Type @test {\n field\n}"
607 );
608 }
609
610 #[test]
611 fn operation_definition() {
612 let ctx = ASTContext::new();
613 let ast = OperationDefinition::parse(
614 &ctx,
615 r#"
616 query {
617 field
618 }
619 "#,
620 );
621 assert_eq!(ast.unwrap().print(), "{\n field\n}");
622
623 let ast = OperationDefinition::parse(
624 &ctx,
625 r#"
626 query Name {
627 field
628 }
629 "#,
630 );
631 assert_eq!(ast.unwrap().print(), "query Name {\n field\n}");
632
633 let ast = OperationDefinition::parse(
634 &ctx,
635 r#"
636 query Name ($var: String) {
637 field
638 }
639 "#,
640 );
641 assert_eq!(
642 ast.unwrap().print(),
643 "query Name($var: String) {\n field\n}"
644 );
645
646 let ast = OperationDefinition::parse(
647 &ctx,
648 r#"
649 query ($var: String) {
650 field
651 }
652 "#,
653 );
654 assert_eq!(ast.unwrap().print(), "query ($var: String) {\n field\n}");
655
656 let ast = OperationDefinition::parse(
657 &ctx,
658 r#"
659 query Name ($var: String) @defer{
660 field
661 }
662 "#,
663 );
664 assert_eq!(
665 ast.unwrap().print(),
666 "query Name($var: String) @defer {\n field\n}"
667 );
668
669 let ast = OperationDefinition::parse(
670 &ctx,
671 r#"
672 mutation {
673 doThing
674 }
675 "#,
676 );
677 assert_eq!(ast.unwrap().print(), "mutation {\n doThing\n}");
678 }
679
680 #[test]
681 fn kitchen_sink() {
682 let ctx = ASTContext::new();
683 let query = include_str!("../../fixture/kitchen_sink.graphql");
684 let ast = Document::parse(&ctx, query);
685 let expected = indoc::indoc! {r#"
686 query queryName($foo: ComplexType, $site: Site = MOBILE) @onQuery {
687 whoever123is: node(id: [123, 456]) {
688 id
689 ... on User @onInlineFragment {
690 field2 {
691 id
692 alias: field1(first: 10, after: $foo) @include(if: $foo) {
693 id
694 ...frag @onFragmentSpread
695 }
696 }
697 }
698 ... @skip(unless: $foo) {
699 id
700 }
701 ... {
702 id
703 }
704 }
705 }
706
707 mutation likeStory @onMutation {
708 like(story: 123) @onField {
709 story {
710 id @onField
711 }
712 }
713 }
714
715 subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) @onSubscription {
716 storyLikeSubscribe(input: $input) {
717 story {
718 likers {
719 count
720 }
721 likeSentence {
722 text
723 }
724 }
725 }
726 }
727
728 fragment frag on Friend @onFragmentDefinition {
729 foo(size: $site, bar: 12, obj: {key: "value", block: """
730 block string uses \"""
731 """})
732 }
733
734 query teeny {
735 unnamed(truthy: true, falsey: false, nullish: null)
736 query
737 }
738
739 query tiny {
740 __typename
741 }"#};
742 assert_eq!(ast.unwrap().print(), expected);
743 }
744}