graphql 1.7.7 → 1.7.8

Sign up to get free protection for your applications and to get access to all the features.
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