graphql 1.7.7 → 1.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql/enum_type.rb +1 -1
  3. data/lib/graphql/field.rb +10 -1
  4. data/lib/graphql/input_object_type.rb +3 -1
  5. data/lib/graphql/introspection/arguments_field.rb +1 -0
  6. data/lib/graphql/introspection/enum_values_field.rb +1 -0
  7. data/lib/graphql/introspection/fields_field.rb +1 -0
  8. data/lib/graphql/introspection/input_fields_field.rb +1 -0
  9. data/lib/graphql/introspection/interfaces_field.rb +1 -0
  10. data/lib/graphql/introspection/of_type_field.rb +1 -0
  11. data/lib/graphql/introspection/possible_types_field.rb +1 -0
  12. data/lib/graphql/introspection/schema_field.rb +1 -0
  13. data/lib/graphql/introspection/type_by_name_field.rb +1 -0
  14. data/lib/graphql/introspection/typename_field.rb +1 -0
  15. data/lib/graphql/language.rb +1 -0
  16. data/lib/graphql/language/document_from_schema_definition.rb +129 -37
  17. data/lib/graphql/language/generation.rb +3 -182
  18. data/lib/graphql/language/nodes.rb +12 -2
  19. data/lib/graphql/language/parser.rb +63 -55
  20. data/lib/graphql/language/parser.y +2 -1
  21. data/lib/graphql/language/printer.rb +351 -0
  22. data/lib/graphql/object_type.rb +1 -1
  23. data/lib/graphql/query/arguments.rb +27 -9
  24. data/lib/graphql/query/literal_input.rb +4 -1
  25. data/lib/graphql/schema/printer.rb +33 -266
  26. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  27. data/lib/graphql/version.rb +1 -1
  28. data/spec/graphql/language/document_from_schema_definition_spec.rb +729 -296
  29. data/spec/graphql/language/generation_spec.rb +21 -186
  30. data/spec/graphql/language/nodes_spec.rb +21 -0
  31. data/spec/graphql/language/printer_spec.rb +203 -0
  32. data/spec/graphql/query/arguments_spec.rb +33 -11
  33. data/spec/graphql/schema/build_from_definition_spec.rb +13 -4
  34. data/spec/graphql/schema/printer_spec.rb +14 -14
  35. metadata +5 -2
@@ -14,189 +14,10 @@ module GraphQL
14
14
  #
15
15
  # @param node [GraphQL::Language::Nodes::AbstractNode] an AST node to recursively stringify
16
16
  # @param indent [String] Whitespace to add to each printed node
17
+ # @param printer [GraphQL::Language::Printer] An optional custom printer for printing AST nodes. Defaults to GraphQL::Language::Printer
17
18
  # @return [String] Valid GraphQL for `node`
18
- def generate(node, indent: "")
19
- case node
20
- when Nodes::Document
21
- node.definitions.map { |d| generate(d) }.join("\n\n")
22
- when Nodes::Argument
23
- "#{node.name}: #{generate(node.value)}".dup
24
- when Nodes::Directive
25
- out = "@#{node.name}".dup
26
- out << "(#{node.arguments.map { |a| generate(a) }.join(", ")})" if node.arguments.any?
27
- out
28
- when Nodes::Enum
29
- "#{node.name}".dup
30
- when Nodes::NullValue
31
- "null".dup
32
- when Nodes::Field
33
- out = "#{indent}".dup
34
- out << "#{node.alias}: " if node.alias
35
- out << "#{node.name}"
36
- out << "(#{node.arguments.map { |a| generate(a) }.join(", ")})" if node.arguments.any?
37
- out << generate_directives(node.directives)
38
- out << generate_selections(node.selections, indent: indent)
39
- out
40
- when Nodes::FragmentDefinition
41
- out = "#{indent}fragment #{node.name}".dup
42
- if node.type
43
- out << " on #{generate(node.type)}"
44
- end
45
- out << generate_directives(node.directives)
46
- out << generate_selections(node.selections, indent: indent)
47
- out
48
- when Nodes::FragmentSpread
49
- out = "#{indent}...#{node.name}".dup
50
- out << generate_directives(node.directives)
51
- out
52
- when Nodes::InlineFragment
53
- out = "#{indent}...".dup
54
- if node.type
55
- out << " on #{generate(node.type)}"
56
- end
57
- out << generate_directives(node.directives)
58
- out << generate_selections(node.selections, indent: indent)
59
- out
60
- when Nodes::InputObject
61
- generate(node.to_h)
62
- when Nodes::ListType
63
- "[#{generate(node.of_type)}]".dup
64
- when Nodes::NonNullType
65
- "#{generate(node.of_type)}!".dup
66
- when Nodes::OperationDefinition
67
- out = "#{indent}#{node.operation_type}".dup
68
- out << " #{node.name}" if node.name
69
- out << "(#{node.variables.map { |v| generate(v) }.join(", ")})" if node.variables.any?
70
- out << generate_directives(node.directives)
71
- out << generate_selections(node.selections, indent: indent)
72
- out
73
- when Nodes::TypeName
74
- "#{node.name}".dup
75
- when Nodes::VariableDefinition
76
- out = "$#{node.name}: #{generate(node.type)}".dup
77
- out << " = #{generate(node.default_value)}" unless node.default_value.nil?
78
- out
79
- when Nodes::VariableIdentifier
80
- "$#{node.name}".dup
81
- when Nodes::SchemaDefinition
82
- if (node.query.nil? || node.query == 'Query') &&
83
- (node.mutation.nil? || node.mutation == 'Mutation') &&
84
- (node.subscription.nil? || node.subscription == 'Subscription')
85
- return
86
- end
87
-
88
- out = "schema {\n".dup
89
- out << " query: #{node.query}\n" if node.query
90
- out << " mutation: #{node.mutation}\n" if node.mutation
91
- out << " subscription: #{node.subscription}\n" if node.subscription
92
- out << "}"
93
- when Nodes::ScalarTypeDefinition
94
- out = generate_description(node)
95
- out << "scalar #{node.name}"
96
- out << generate_directives(node.directives)
97
- when Nodes::ObjectTypeDefinition
98
- out = generate_description(node)
99
- out << "type #{node.name}"
100
- out << generate_directives(node.directives)
101
- out << " implements " << node.interfaces.map(&:name).join(", ") unless node.interfaces.empty?
102
- out << generate_field_definitions(node.fields)
103
- when Nodes::InputValueDefinition
104
- out = "#{node.name}: #{generate(node.type)}".dup
105
- out << " = #{generate(node.default_value)}" unless node.default_value.nil?
106
- out << generate_directives(node.directives)
107
- when Nodes::FieldDefinition
108
- out = node.name.dup
109
- unless node.arguments.empty?
110
- out << "(" << node.arguments.map{ |arg| generate(arg) }.join(", ") << ")"
111
- end
112
- out << ": #{generate(node.type)}"
113
- out << generate_directives(node.directives)
114
- when Nodes::InterfaceTypeDefinition
115
- out = generate_description(node)
116
- out << "interface #{node.name}"
117
- out << generate_directives(node.directives)
118
- out << generate_field_definitions(node.fields)
119
- when Nodes::UnionTypeDefinition
120
- out = generate_description(node)
121
- out << "union #{node.name}"
122
- out << generate_directives(node.directives)
123
- out << " = " + node.types.map(&:name).join(" | ")
124
- when Nodes::EnumTypeDefinition
125
- out = generate_description(node)
126
- out << "enum #{node.name}#{generate_directives(node.directives)} {\n"
127
- node.values.each.with_index do |value, i|
128
- out << generate_description(value, indent: ' ', first_in_block: i == 0)
129
- out << generate(value)
130
- end
131
- out << "}"
132
- when Nodes::EnumValueDefinition
133
- out = " #{node.name}".dup
134
- out << generate_directives(node.directives)
135
- out << "\n"
136
- when Nodes::InputObjectTypeDefinition
137
- out = generate_description(node)
138
- out << "input #{node.name}"
139
- out << generate_directives(node.directives)
140
- out << " {\n"
141
- node.fields.each.with_index do |field, i|
142
- out << generate_description(field, indent: ' ', first_in_block: i == 0)
143
- out << " #{generate(field)}\n"
144
- end
145
- out << "}"
146
- when Nodes::DirectiveDefinition
147
- out = generate_description(node)
148
- out << "directive @#{node.name}"
149
- out << "(#{node.arguments.map { |a| generate(a) }.join(", ")})" if node.arguments.any?
150
- out << " on #{node.locations.join(' | ')}"
151
- when Nodes::AbstractNode
152
- node.to_query_string(indent: indent)
153
- when FalseClass, Float, Integer, NilClass, String, TrueClass
154
- GraphQL::Language.serialize(node)
155
- when Array
156
- "[#{node.map { |v| generate(v) }.join(", ")}]".dup
157
- when Hash
158
- "{#{node.map { |k, v| "#{k}: #{generate(v)}" }.join(", ")}}".dup
159
- else
160
- raise TypeError
161
- end
162
- end
163
-
164
- private
165
-
166
- def generate_directives(directives)
167
- if directives.any?
168
- directives.map { |d| " #{generate(d)}" }.join
169
- else
170
- ""
171
- end
172
- end
173
-
174
- def generate_selections(selections, indent: "")
175
- if selections.any?
176
- out = " {\n".dup
177
- selections.each do |selection|
178
- out << generate(selection, indent: indent + " ") << "\n"
179
- end
180
- out << "#{indent}}"
181
- else
182
- ""
183
- end
184
- end
185
-
186
- def generate_description(node, indent: '', first_in_block: true)
187
- return ''.dup unless node.description
188
-
189
- description = indent != '' && !first_in_block ? "\n".dup : "".dup
190
- description << GraphQL::Language::Comments.commentize(node.description, indent: indent)
191
- end
192
-
193
- def generate_field_definitions(fields)
194
- out = " {\n".dup
195
- fields.each.with_index do |field, i|
196
- out << generate_description(field, indent: ' ', first_in_block: i == 0)
197
- out << " #{generate(field)}\n"
198
- end
199
- out << "}"
19
+ def generate(node, indent: "", printer: GraphQL::Language::Printer.new)
20
+ printer.print(node, indent: indent)
200
21
  end
201
22
  end
202
23
  end
@@ -8,6 +8,7 @@ module GraphQL
8
8
  # - `children` returns all AST nodes attached to this one. Used for tree traversal.
9
9
  # - `scalars` returns all scalar (Ruby) values attached to this one. Used for comparing nodes.
10
10
  # - `to_query_string` turns an AST node into a GraphQL string
11
+
11
12
  class AbstractNode
12
13
  attr_accessor :line, :col, :filename
13
14
 
@@ -77,8 +78,8 @@ module GraphQL
77
78
  [line, col]
78
79
  end
79
80
 
80
- def to_query_string
81
- Generation.generate(self)
81
+ def to_query_string(printer: GraphQL::Language::Printer.new)
82
+ printer.print(self)
82
83
  end
83
84
  end
84
85
 
@@ -164,6 +165,15 @@ module GraphQL
164
165
  # document.to_query_string
165
166
  # # { ... }
166
167
  #
168
+ # @example Creating a custom string from a document
169
+ # class VariableScrubber < GraphQL::Language::Printer
170
+ # def print_argument(arg)
171
+ # "#{arg.name}: <HIDDEN>"
172
+ # end
173
+ # end
174
+ #
175
+ # document.to_query_string(printer: VariableSrubber.new)
176
+ #
167
177
  class Document < AbstractNode
168
178
  attr_accessor :definitions
169
179
  child_attributes :definitions
@@ -12,7 +12,7 @@ module GraphQL
12
12
  module Language
13
13
  class Parser < Racc::Parser
14
14
 
15
- module_eval(<<'...end parser.y/module_eval...', 'parser.y', 372)
15
+ module_eval(<<'...end parser.y/module_eval...', 'parser.y', 373)
16
16
 
17
17
  def initialize(query_string, filename:, tracer: Tracing::NullTracer)
18
18
  @query_string = query_string
@@ -425,30 +425,30 @@ racc_action_pointer = [
425
425
  nil, nil, nil, nil ]
426
426
 
427
427
  racc_action_default = [
428
- -145, -145, -1, -2, -3, -5, -6, -7, -14, -145,
429
- -11, -12, -13, -109, -111, -112, -113, -145, -118, -119,
430
- -120, -121, -122, -123, -145, -145, -145, -145, -145, -145,
431
- -145, -145, -4, -16, -15, -37, -38, -39, -40, -41,
428
+ -146, -146, -1, -2, -3, -5, -6, -7, -14, -146,
429
+ -11, -12, -13, -109, -111, -112, -113, -146, -118, -119,
430
+ -120, -121, -122, -123, -146, -146, -146, -146, -146, -146,
431
+ -146, -146, -4, -16, -15, -37, -38, -39, -40, -41,
432
432
  -42, -43, -44, -45, -46, -47, -48, -49, -50, -51,
433
- -52, -53, -145, -10, -30, -32, -33, -34, -64, -100,
434
- -145, -110, -145, -100, -126, -100, -100, -100, -100, -145,
435
- 244, -100, -145, -9, -31, -100, -145, -145, -101, -102,
436
- -145, -100, -145, -145, -145, -145, -115, -145, -124, -100,
437
- -145, -145, -145, -145, -145, -131, -145, -145, -18, -145,
438
- -28, -64, -65, -145, -67, -145, -103, -64, -105, -21,
439
- -100, -145, -145, -107, -100, -114, -116, -145, -145, -59,
440
- -127, -145, -145, -145, -145, -145, -145, -8, -17, -19,
441
- -145, -29, -35, -100, -66, -68, -79, -104, -22, -145,
442
- -145, -26, -145, -145, -117, -145, -60, -131, -134, -145,
443
- -137, -139, -54, -55, -56, -57, -58, -100, -62, -145,
444
- -145, -129, -145, -145, -145, -145, -28, -69, -70, -71,
433
+ -52, -53, -146, -10, -30, -32, -33, -34, -64, -100,
434
+ -146, -110, -146, -100, -126, -100, -100, -100, -100, -146,
435
+ 244, -100, -146, -9, -31, -100, -146, -146, -101, -102,
436
+ -146, -100, -146, -146, -146, -146, -115, -146, -124, -100,
437
+ -146, -146, -146, -146, -146, -131, -146, -146, -18, -146,
438
+ -28, -64, -65, -146, -67, -146, -103, -64, -105, -21,
439
+ -100, -146, -146, -107, -100, -114, -116, -146, -146, -59,
440
+ -127, -134, -146, -146, -146, -146, -146, -8, -17, -19,
441
+ -146, -29, -35, -100, -66, -68, -79, -104, -22, -146,
442
+ -146, -26, -146, -146, -117, -134, -60, -131, -135, -146,
443
+ -138, -140, -54, -55, -56, -57, -58, -100, -62, -146,
444
+ -146, -129, -146, -146, -146, -146, -28, -69, -70, -71,
445
445
  -72, -73, -74, -75, -76, -77, -78, -80, -81, -82,
446
- -83, -145, -145, -145, -99, -106, -23, -27, -108, -145,
447
- -145, -135, -136, -145, -61, -63, -140, -145, -130, -141,
448
- -132, -142, -143, -24, -36, -84, -85, -145, -87, -89,
449
- -145, -91, -145, -145, -96, -125, -145, -138, -24, -145,
450
- -20, -145, -86, -88, -90, -92, -145, -79, -95, -97,
451
- -145, -100, -100, -144, -25, -145, -79, -80, -93, -145,
446
+ -83, -146, -146, -146, -99, -106, -23, -27, -108, -146,
447
+ -146, -136, -137, -146, -61, -63, -141, -146, -130, -142,
448
+ -132, -143, -144, -24, -36, -84, -85, -146, -87, -89,
449
+ -146, -91, -146, -146, -96, -125, -146, -139, -24, -146,
450
+ -20, -146, -86, -88, -90, -92, -146, -79, -95, -97,
451
+ -146, -100, -100, -145, -25, -146, -79, -80, -93, -146,
452
452
  -133, -128, -94, -98 ]
453
453
 
454
454
  racc_goto_table = [
@@ -656,19 +656,20 @@ racc_reduce_table = [
656
656
  0, 100, :_reduce_131,
657
657
  3, 100, :_reduce_132,
658
658
  5, 101, :_reduce_133,
659
- 1, 97, :_reduce_134,
660
- 2, 97, :_reduce_135,
661
- 6, 92, :_reduce_136,
662
- 1, 102, :_reduce_137,
663
- 3, 102, :_reduce_138,
664
- 5, 93, :_reduce_139,
665
- 6, 94, :_reduce_140,
666
- 6, 95, :_reduce_141,
667
- 6, 87, :_reduce_142,
668
- 1, 103, :_reduce_143,
669
- 3, 103, :_reduce_144 ]
670
-
671
- racc_reduce_n = 145
659
+ 0, 97, :_reduce_134,
660
+ 1, 97, :_reduce_135,
661
+ 2, 97, :_reduce_136,
662
+ 6, 92, :_reduce_137,
663
+ 1, 102, :_reduce_138,
664
+ 3, 102, :_reduce_139,
665
+ 5, 93, :_reduce_140,
666
+ 6, 94, :_reduce_141,
667
+ 6, 95, :_reduce_142,
668
+ 6, 87, :_reduce_143,
669
+ 1, 103, :_reduce_144,
670
+ 3, 103, :_reduce_145 ]
671
+
672
+ racc_reduce_n = 146
672
673
 
673
674
  racc_shift_n = 244
674
675
 
@@ -1582,81 +1583,88 @@ module_eval(<<'.,.,', 'parser.y', 326)
1582
1583
 
1583
1584
  module_eval(<<'.,.,', 'parser.y', 330)
1584
1585
  def _reduce_134(val, _values, result)
1585
- return [val[0]]
1586
+ return []
1586
1587
  result
1587
1588
  end
1588
1589
  .,.,
1589
1590
 
1590
1591
  module_eval(<<'.,.,', 'parser.y', 331)
1591
1592
  def _reduce_135(val, _values, result)
1592
- val[0] << val[1]
1593
+ return [val[0]]
1593
1594
  result
1594
1595
  end
1595
1596
  .,.,
1596
1597
 
1597
- module_eval(<<'.,.,', 'parser.y', 335)
1598
+ module_eval(<<'.,.,', 'parser.y', 332)
1598
1599
  def _reduce_136(val, _values, result)
1599
- return make_node(:InterfaceTypeDefinition, name: val[1], directives: val[2], fields: val[4], description: get_description(val[0]), position_source: val[0])
1600
-
1600
+ val[0] << val[1]
1601
1601
  result
1602
1602
  end
1603
1603
  .,.,
1604
1604
 
1605
- module_eval(<<'.,.,', 'parser.y', 339)
1605
+ module_eval(<<'.,.,', 'parser.y', 336)
1606
1606
  def _reduce_137(val, _values, result)
1607
- return [make_node(:TypeName, name: val[0])]
1607
+ return make_node(:InterfaceTypeDefinition, name: val[1], directives: val[2], fields: val[4], description: get_description(val[0]), position_source: val[0])
1608
+
1608
1609
  result
1609
1610
  end
1610
1611
  .,.,
1611
1612
 
1612
1613
  module_eval(<<'.,.,', 'parser.y', 340)
1613
1614
  def _reduce_138(val, _values, result)
1614
- val[0] << make_node(:TypeName, name: val[2])
1615
+ return [make_node(:TypeName, name: val[0])]
1615
1616
  result
1616
1617
  end
1617
1618
  .,.,
1618
1619
 
1619
- module_eval(<<'.,.,', 'parser.y', 344)
1620
+ module_eval(<<'.,.,', 'parser.y', 341)
1620
1621
  def _reduce_139(val, _values, result)
1621
- return make_node(:UnionTypeDefinition, name: val[1], directives: val[2], types: val[4], description: get_description(val[0]), position_source: val[0])
1622
-
1622
+ val[0] << make_node(:TypeName, name: val[2])
1623
1623
  result
1624
1624
  end
1625
1625
  .,.,
1626
1626
 
1627
- module_eval(<<'.,.,', 'parser.y', 349)
1627
+ module_eval(<<'.,.,', 'parser.y', 345)
1628
1628
  def _reduce_140(val, _values, result)
1629
- return make_node(:EnumTypeDefinition, name: val[1], directives: val[2], values: val[4], description: get_description(val[0]), position_source: val[0])
1629
+ return make_node(:UnionTypeDefinition, name: val[1], directives: val[2], types: val[4], description: get_description(val[0]), position_source: val[0])
1630
1630
 
1631
1631
  result
1632
1632
  end
1633
1633
  .,.,
1634
1634
 
1635
- module_eval(<<'.,.,', 'parser.y', 354)
1635
+ module_eval(<<'.,.,', 'parser.y', 350)
1636
1636
  def _reduce_141(val, _values, result)
1637
- return make_node(:InputObjectTypeDefinition, name: val[1], directives: val[2], fields: val[4], description: get_description(val[0]), position_source: val[0])
1637
+ return make_node(:EnumTypeDefinition, name: val[1], directives: val[2], values: val[4], description: get_description(val[0]), position_source: val[0])
1638
1638
 
1639
1639
  result
1640
1640
  end
1641
1641
  .,.,
1642
1642
 
1643
- module_eval(<<'.,.,', 'parser.y', 359)
1643
+ module_eval(<<'.,.,', 'parser.y', 355)
1644
1644
  def _reduce_142(val, _values, result)
1645
- return make_node(:DirectiveDefinition, name: val[2], arguments: val[3], locations: val[5], description: get_description(val[0]), position_source: val[0])
1645
+ return make_node(:InputObjectTypeDefinition, name: val[1], directives: val[2], fields: val[4], description: get_description(val[0]), position_source: val[0])
1646
1646
 
1647
1647
  result
1648
1648
  end
1649
1649
  .,.,
1650
1650
 
1651
- module_eval(<<'.,.,', 'parser.y', 363)
1651
+ module_eval(<<'.,.,', 'parser.y', 360)
1652
1652
  def _reduce_143(val, _values, result)
1653
- return [val[0].to_s]
1653
+ return make_node(:DirectiveDefinition, name: val[2], arguments: val[3], locations: val[5], description: get_description(val[0]), position_source: val[0])
1654
+
1654
1655
  result
1655
1656
  end
1656
1657
  .,.,
1657
1658
 
1658
1659
  module_eval(<<'.,.,', 'parser.y', 364)
1659
1660
  def _reduce_144(val, _values, result)
1661
+ return [val[0].to_s]
1662
+ result
1663
+ end
1664
+ .,.,
1665
+
1666
+ module_eval(<<'.,.,', 'parser.y', 365)
1667
+ def _reduce_145(val, _values, result)
1660
1668
  val[0] << val[2].to_s
1661
1669
  result
1662
1670
  end
@@ -328,7 +328,8 @@ rule
328
328
  }
329
329
 
330
330
  field_definition_list:
331
- field_definition { return [val[0]] }
331
+ /* none */ { return [] }
332
+ | field_definition { return [val[0]] }
332
333
  | field_definition_list field_definition { val[0] << val[1] }
333
334
 
334
335
  interface_type_definition:
@@ -0,0 +1,351 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Language
4
+ class Printer
5
+ # Turn an arbitrary AST node back into a string.
6
+ #
7
+ # @example Turning a document into a query string
8
+ # document = GraphQL.parse(query_string)
9
+ # GraphQL::Language::Printer.new.print(document)
10
+ # # => "{ ... }"
11
+ #
12
+ #
13
+ # @example Building a custom printer
14
+ #
15
+ # class MyPrinter < GraphQL::Language::Printer
16
+ # def print_argument(arg)
17
+ # "#{arg.name}: <HIDDEN>"
18
+ # end
19
+ # end
20
+ #
21
+ # MyPrinter.new.print(document)
22
+ # # => "mutation { pay(creditCard: <HIDDEN>) { success } }"
23
+ #
24
+ #
25
+ # @param indent [String] Whitespace to add to the printed node
26
+ # @return [String] Valid GraphQL for `node`
27
+ def print(node, indent: "")
28
+ print_node(node, indent: indent)
29
+ end
30
+
31
+ protected
32
+
33
+ def print_document(document)
34
+ document.definitions.map { |d| print_node(d) }.join("\n\n")
35
+ end
36
+
37
+ def print_argument(argument)
38
+ "#{argument.name}: #{print_node(argument.value)}".dup
39
+ end
40
+
41
+ def print_directive(directive)
42
+ out = "@#{directive.name}".dup
43
+
44
+ if directive.arguments.any?
45
+ out << "(#{directive.arguments.map { |a| print_argument(a) }.join(", ")})"
46
+ end
47
+
48
+ out
49
+ end
50
+
51
+ def print_enum(enum)
52
+ "#{enum.name}".dup
53
+ end
54
+
55
+ def print_null_value
56
+ "null".dup
57
+ end
58
+
59
+ def print_field(field, indent: "")
60
+ out = "#{indent}".dup
61
+ out << "#{field.alias}: " if field.alias
62
+ out << "#{field.name}"
63
+ out << "(#{field.arguments.map { |a| print_argument(a) }.join(", ")})" if field.arguments.any?
64
+ out << print_directives(field.directives)
65
+ out << print_selections(field.selections, indent: indent)
66
+ out
67
+ end
68
+
69
+ def print_fragment_definition(fragment_def, indent: "")
70
+ out = "#{indent}fragment #{fragment_def.name}".dup
71
+ if fragment_def.type
72
+ out << " on #{print_node(fragment_def.type)}"
73
+ end
74
+ out << print_directives(fragment_def.directives)
75
+ out << print_selections(fragment_def.selections, indent: indent)
76
+ out
77
+ end
78
+
79
+ def print_fragment_spread(fragment_spread, indent: "")
80
+ out = "#{indent}...#{fragment_spread.name}".dup
81
+ out << print_directives(fragment_spread.directives)
82
+ out
83
+ end
84
+
85
+ def print_inline_fragment(inline_fragment, indent: "")
86
+ out = "#{indent}...".dup
87
+ if inline_fragment.type
88
+ out << " on #{print_node(inline_fragment.type)}"
89
+ end
90
+ out << print_directives(inline_fragment.directives)
91
+ out << print_selections(inline_fragment.selections, indent: indent)
92
+ out
93
+ end
94
+
95
+ def print_input_object(input_object)
96
+ print_node(input_object.to_h)
97
+ end
98
+
99
+ def print_list_type(list_type)
100
+ "[#{print_node(list_type.of_type)}]".dup
101
+ end
102
+
103
+ def print_non_null_type(non_null_type)
104
+ "#{print_node(non_null_type.of_type)}!".dup
105
+ end
106
+
107
+ def print_operation_definition(operation_definition, indent: "")
108
+ out = "#{indent}#{operation_definition.operation_type}".dup
109
+ out << " #{operation_definition.name}" if operation_definition.name
110
+
111
+ if operation_definition.variables.any?
112
+ out << "(#{operation_definition.variables.map { |v| print_variable_definition(v) }.join(", ")})"
113
+ end
114
+
115
+ out << print_directives(operation_definition.directives)
116
+ out << print_selections(operation_definition.selections, indent: indent)
117
+ out
118
+ end
119
+
120
+ def print_type_name(type_name)
121
+ "#{type_name.name}".dup
122
+ end
123
+
124
+ def print_variable_definition(variable_definition)
125
+ out = "$#{variable_definition.name}: #{print_node(variable_definition.type)}".dup
126
+ out << " = #{print_node(variable_definition.default_value)}" unless variable_definition.default_value.nil?
127
+ out
128
+ end
129
+
130
+ def print_variable_identifier(variable_identifier)
131
+ "$#{variable_identifier.name}".dup
132
+ end
133
+
134
+ def print_schema_definition(schema)
135
+ if (schema.query.nil? || schema.query == 'Query') &&
136
+ (schema.mutation.nil? || schema.mutation == 'Mutation') &&
137
+ (schema.subscription.nil? || schema.subscription == 'Subscription')
138
+ return
139
+ end
140
+
141
+ out = "schema {\n".dup
142
+ out << " query: #{schema.query}\n" if schema.query
143
+ out << " mutation: #{schema.mutation}\n" if schema.mutation
144
+ out << " subscription: #{schema.subscription}\n" if schema.subscription
145
+ out << "}"
146
+ end
147
+
148
+ def print_scalar_type_definition(scalar_type)
149
+ out = print_description(scalar_type)
150
+ out << "scalar #{scalar_type.name}"
151
+ out << print_directives(scalar_type.directives)
152
+ end
153
+
154
+ def print_object_type_definition(object_type)
155
+ out = print_description(object_type)
156
+ out << "type #{object_type.name}"
157
+ out << print_directives(object_type.directives)
158
+ out << " implements " << object_type.interfaces.map(&:name).join(", ") unless object_type.interfaces.empty?
159
+ out << print_field_definitions(object_type.fields)
160
+ end
161
+
162
+ def print_input_value_definition(input_value)
163
+ out = "#{input_value.name}: #{print_node(input_value.type)}".dup
164
+ out << " = #{print_node(input_value.default_value)}" unless input_value.default_value.nil?
165
+ out << print_directives(input_value.directives)
166
+ end
167
+
168
+ def print_arguments(arguments, indent: "")
169
+ if arguments.all?{ |arg| !arg.description }
170
+ return "(#{arguments.map{ |arg| print_input_value_definition(arg) }.join(", ")})"
171
+ end
172
+
173
+ out = "(\n".dup
174
+ out << arguments.map.with_index{ |arg, i|
175
+ "#{print_description(arg, indent: " " + indent, first_in_block: i == 0)} #{indent}"\
176
+ "#{print_input_value_definition(arg)}"
177
+ }.join("\n")
178
+ out << "\n#{indent})"
179
+ end
180
+
181
+ def print_field_definition(field)
182
+ out = field.name.dup
183
+ unless field.arguments.empty?
184
+ out << print_arguments(field.arguments, indent: " ")
185
+ end
186
+ out << ": #{print_node(field.type)}"
187
+ out << print_directives(field.directives)
188
+ end
189
+
190
+ def print_interface_type_definition(interface_type)
191
+ out = print_description(interface_type)
192
+ out << "interface #{interface_type.name}"
193
+ out << print_directives(interface_type.directives)
194
+ out << print_field_definitions(interface_type.fields)
195
+ end
196
+
197
+ def print_union_type_definition(union_type)
198
+ out = print_description(union_type)
199
+ out << "union #{union_type.name}"
200
+ out << print_directives(union_type.directives)
201
+ out << " = " + union_type.types.map(&:name).join(" | ")
202
+ end
203
+
204
+ def print_enum_type_definition(enum_type)
205
+ out = print_description(enum_type)
206
+ out << "enum #{enum_type.name}#{print_directives(enum_type.directives)} {\n"
207
+ enum_type.values.each.with_index do |value, i|
208
+ out << print_description(value, indent: ' ', first_in_block: i == 0)
209
+ out << print_enum_value_definition(value)
210
+ end
211
+ out << "}"
212
+ end
213
+
214
+ def print_enum_value_definition(enum_value)
215
+ out = " #{enum_value.name}".dup
216
+ out << print_directives(enum_value.directives)
217
+ out << "\n"
218
+ end
219
+
220
+ def print_input_object_type_definition(input_object_type)
221
+ out = print_description(input_object_type)
222
+ out << "input #{input_object_type.name}"
223
+ out << print_directives(input_object_type.directives)
224
+ out << " {\n"
225
+ input_object_type.fields.each.with_index do |field, i|
226
+ out << print_description(field, indent: ' ', first_in_block: i == 0)
227
+ out << " #{print_input_value_definition(field)}\n"
228
+ end
229
+ out << "}"
230
+ end
231
+
232
+ def print_directive_definition(directive)
233
+ out = print_description(directive)
234
+ out << "directive @#{directive.name}"
235
+
236
+ if directive.arguments.any?
237
+ out << print_arguments(directive.arguments)
238
+ end
239
+
240
+ out << " on #{directive.locations.join(' | ')}"
241
+ end
242
+
243
+ def print_description(node, indent: "", first_in_block: true)
244
+ return ''.dup unless node.description
245
+
246
+ description = indent != '' && !first_in_block ? "\n".dup : "".dup
247
+ description << GraphQL::Language::Comments.commentize(node.description, indent: indent)
248
+ end
249
+
250
+ def print_field_definitions(fields)
251
+ out = " {\n".dup
252
+ fields.each.with_index do |field, i|
253
+ out << print_description(field, indent: ' ', first_in_block: i == 0)
254
+ out << " #{print_field_definition(field)}\n"
255
+ end
256
+ out << "}"
257
+ end
258
+
259
+ def print_directives(directives)
260
+ if directives.any?
261
+ directives.map { |d| " #{print_directive(d)}" }.join
262
+ else
263
+ ""
264
+ end
265
+ end
266
+
267
+ def print_selections(selections, indent: "")
268
+ if selections.any?
269
+ out = " {\n".dup
270
+ selections.each do |selection|
271
+ out << print_node(selection, indent: indent + " ") << "\n"
272
+ end
273
+ out << "#{indent}}"
274
+ else
275
+ ""
276
+ end
277
+ end
278
+
279
+ def print_node(node, indent: "")
280
+ case node
281
+ when Nodes::Document
282
+ print_document(node)
283
+ when Nodes::Argument
284
+ print_argument(node)
285
+ when Nodes::Directive
286
+ print_directive(node)
287
+ when Nodes::Enum
288
+ print_enum(node)
289
+ when Nodes::NullValue
290
+ print_null_value
291
+ when Nodes::Field
292
+ print_field(node, indent: indent)
293
+ when Nodes::FragmentDefinition
294
+ print_fragment_definition(node, indent: indent)
295
+ when Nodes::FragmentSpread
296
+ print_fragment_spread(node, indent: indent)
297
+ when Nodes::InlineFragment
298
+ print_inline_fragment(node, indent: indent)
299
+ when Nodes::InputObject
300
+ print_input_object(node)
301
+ when Nodes::ListType
302
+ print_list_type(node)
303
+ when Nodes::NonNullType
304
+ print_non_null_type(node)
305
+ when Nodes::OperationDefinition
306
+ print_operation_definition(node, indent: indent)
307
+ when Nodes::TypeName
308
+ print_type_name(node)
309
+ when Nodes::VariableDefinition
310
+ print_variable_definition(node)
311
+ when Nodes::VariableIdentifier
312
+ print_variable_identifier(node)
313
+ when Nodes::SchemaDefinition
314
+ print_schema_definition(node)
315
+ when Nodes::ScalarTypeDefinition
316
+ print_scalar_type_definition(node)
317
+ when Nodes::ObjectTypeDefinition
318
+ print_object_type_definition(node)
319
+ when Nodes::InputValueDefinition
320
+ print_input_value_definition(node)
321
+ when Nodes::FieldDefinition
322
+ print_field_definition(node)
323
+ when Nodes::InterfaceTypeDefinition
324
+ print_interface_type_definition(node)
325
+ when Nodes::UnionTypeDefinition
326
+ print_union_type_definition(node)
327
+ when Nodes::EnumTypeDefinition
328
+ print_enum_type_definition(node)
329
+ when Nodes::EnumValueDefinition
330
+ print_enum_value_definition(node)
331
+ when Nodes::InputObjectTypeDefinition
332
+ print_input_object_type_definition(node)
333
+ when Nodes::DirectiveDefinition
334
+ print_directive_definition(node)
335
+ when FalseClass, Float, Integer, NilClass, String, TrueClass, Symbol
336
+ GraphQL::Language.serialize(node)
337
+ when Array
338
+ "[#{node.map { |v| print_node(v) }.join(", ")}]".dup
339
+ when Hash
340
+ "{#{node.map { |k, v| "#{k}: #{print_node(v)}" }.join(", ")}}".dup
341
+ else
342
+ raise TypeError
343
+ end
344
+ end
345
+
346
+ private
347
+
348
+ attr_reader :node
349
+ end
350
+ end
351
+ end