graphql 1.8.0.pre2 → 1.8.0.pre3

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/lib/graphql.rb +1 -1
  3. data/lib/graphql/deprecated_dsl.rb +2 -0
  4. data/lib/graphql/enum_type.rb +1 -1
  5. data/lib/graphql/field.rb +10 -1
  6. data/lib/graphql/input_object_type.rb +3 -1
  7. data/lib/graphql/introspection.rb +3 -10
  8. data/lib/graphql/introspection/base_object.rb +15 -0
  9. data/lib/graphql/introspection/directive_location_enum.rb +11 -7
  10. data/lib/graphql/introspection/directive_type.rb +23 -16
  11. data/lib/graphql/introspection/dynamic_fields.rb +11 -0
  12. data/lib/graphql/introspection/entry_points.rb +29 -0
  13. data/lib/graphql/introspection/enum_value_type.rb +16 -11
  14. data/lib/graphql/introspection/field_type.rb +21 -12
  15. data/lib/graphql/introspection/input_value_type.rb +26 -23
  16. data/lib/graphql/introspection/schema_field.rb +7 -2
  17. data/lib/graphql/introspection/schema_type.rb +36 -22
  18. data/lib/graphql/introspection/type_by_name_field.rb +10 -2
  19. data/lib/graphql/introspection/type_kind_enum.rb +10 -6
  20. data/lib/graphql/introspection/type_type.rb +85 -23
  21. data/lib/graphql/introspection/typename_field.rb +1 -0
  22. data/lib/graphql/language.rb +1 -0
  23. data/lib/graphql/language/document_from_schema_definition.rb +129 -37
  24. data/lib/graphql/language/generation.rb +3 -182
  25. data/lib/graphql/language/nodes.rb +12 -2
  26. data/lib/graphql/language/parser.rb +63 -55
  27. data/lib/graphql/language/parser.y +2 -1
  28. data/lib/graphql/language/printer.rb +351 -0
  29. data/lib/graphql/object_type.rb +1 -1
  30. data/lib/graphql/query.rb +1 -1
  31. data/lib/graphql/query/arguments.rb +24 -8
  32. data/lib/graphql/query/context.rb +3 -0
  33. data/lib/graphql/query/literal_input.rb +4 -1
  34. data/lib/graphql/railtie.rb +28 -6
  35. data/lib/graphql/schema.rb +42 -7
  36. data/lib/graphql/schema/enum.rb +1 -0
  37. data/lib/graphql/schema/field.rb +26 -5
  38. data/lib/graphql/schema/field/dynamic_resolve.rb +18 -9
  39. data/lib/graphql/schema/input_object.rb +2 -2
  40. data/lib/graphql/schema/introspection_system.rb +93 -0
  41. data/lib/graphql/schema/late_bound_type.rb +32 -0
  42. data/lib/graphql/schema/member.rb +21 -1
  43. data/lib/graphql/schema/member/build_type.rb +8 -6
  44. data/lib/graphql/schema/member/has_fields.rb +1 -1
  45. data/lib/graphql/schema/member/instrumentation.rb +3 -1
  46. data/lib/graphql/schema/member/list_type_proxy.rb +4 -0
  47. data/lib/graphql/schema/member/non_null_type_proxy.rb +4 -0
  48. data/lib/graphql/schema/object.rb +2 -1
  49. data/lib/graphql/schema/printer.rb +33 -266
  50. data/lib/graphql/schema/traversal.rb +74 -6
  51. data/lib/graphql/schema/validation.rb +3 -2
  52. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +6 -6
  53. data/lib/graphql/tracing/scout_tracing.rb +2 -2
  54. data/lib/graphql/upgrader/member.rb +463 -63
  55. data/lib/graphql/version.rb +1 -1
  56. data/spec/fixtures/upgrader/blame_range.original.rb +43 -0
  57. data/spec/fixtures/upgrader/blame_range.transformed.rb +31 -0
  58. data/spec/fixtures/upgrader/subscribable.original.rb +51 -0
  59. data/spec/fixtures/upgrader/subscribable.transformed.rb +46 -0
  60. data/spec/fixtures/upgrader/type_x.original.rb +35 -0
  61. data/spec/fixtures/upgrader/type_x.transformed.rb +35 -0
  62. data/spec/graphql/language/document_from_schema_definition_spec.rb +729 -296
  63. data/spec/graphql/language/generation_spec.rb +21 -186
  64. data/spec/graphql/language/nodes_spec.rb +21 -0
  65. data/spec/graphql/language/printer_spec.rb +203 -0
  66. data/spec/graphql/query/arguments_spec.rb +14 -4
  67. data/spec/graphql/query/context_spec.rb +17 -0
  68. data/spec/graphql/schema/build_from_definition_spec.rb +13 -4
  69. data/spec/graphql/schema/field_spec.rb +14 -0
  70. data/spec/graphql/schema/introspection_system_spec.rb +39 -0
  71. data/spec/graphql/schema/object_spec.rb +12 -1
  72. data/spec/graphql/schema/printer_spec.rb +14 -14
  73. data/spec/graphql/tracing/platform_tracing_spec.rb +2 -2
  74. data/spec/graphql/upgrader/member_spec.rb +274 -62
  75. data/spec/support/jazz.rb +75 -3
  76. metadata +38 -9
  77. data/lib/graphql/introspection/arguments_field.rb +0 -7
  78. data/lib/graphql/introspection/enum_values_field.rb +0 -18
  79. data/lib/graphql/introspection/fields_field.rb +0 -13
  80. data/lib/graphql/introspection/input_fields_field.rb +0 -12
  81. data/lib/graphql/introspection/interfaces_field.rb +0 -11
  82. data/lib/graphql/introspection/of_type_field.rb +0 -6
  83. data/lib/graphql/introspection/possible_types_field.rb +0 -11
@@ -4,10 +4,18 @@ module GraphQL
4
4
  TypeByNameField = GraphQL::Field.define do
5
5
  name("__type")
6
6
  description("A type in the GraphQL system")
7
- type(GraphQL::Introspection::TypeType)
7
+ introspection true
8
+ type(GraphQL::Schema::LateBoundType.new("__Type"))
8
9
  argument :name, !types.String
9
10
  resolve ->(o, args, ctx) {
10
- ctx.warden.get_type(args["name"])
11
+ type = ctx.warden.get_type(args["name"])
12
+ if type
13
+ # Apply wrapping manually since this field isn't wrapped by instrumentation
14
+ type_type = ctx.schema.introspection_system.type_type
15
+ type_type.metadata[:object_class].new(type, ctx)
16
+ else
17
+ nil
18
+ end
11
19
  }
12
20
  end
13
21
  end
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Introspection::TypeKindEnum = GraphQL::EnumType.define do
3
- name "__TypeKind"
4
- description "An enum describing what kind of type a given `__Type` is."
5
- GraphQL::TypeKinds::TYPE_KINDS.each do |type_kind|
6
- value(type_kind.name, type_kind.description)
2
+ module GraphQL
3
+ module Introspection
4
+ class TypeKindEnum < GraphQL::Schema::Enum
5
+ graphql_name "__TypeKind"
6
+ description "An enum describing what kind of type a given `__Type` is."
7
+ GraphQL::TypeKinds::TYPE_KINDS.each do |type_kind|
8
+ value(type_kind.name, type_kind.description)
9
+ end
10
+ introspection true
11
+ end
7
12
  end
8
- introspection true
9
13
  end
@@ -1,26 +1,88 @@
1
1
  # frozen_string_literal: true
2
- GraphQL::Introspection::TypeType = GraphQL::ObjectType.define do
3
- name "__Type"
4
- description "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in "\
5
- "GraphQL as represented by the `__TypeKind` enum.\n\n"\
6
- "Depending on the kind of a type, certain fields describe information about that type. "\
7
- "Scalar types provide no information beyond a name and description, while "\
8
- "Enum types provide their values. Object and Interface types provide the fields "\
9
- "they describe. Abstract types, Union and Interface, provide the Object types "\
10
- "possible at runtime. List and NonNull types compose other types."
11
-
12
- field :kind do
13
- type !GraphQL::Introspection::TypeKindEnum
14
- resolve ->(target, a, c) { target.kind.name }
15
- end
2
+ module GraphQL
3
+ module Introspection
4
+ class TypeType < GraphQL::Schema::Object
5
+ graphql_name "__Type"
6
+ description "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in "\
7
+ "GraphQL as represented by the `__TypeKind` enum.\n\n"\
8
+ "Depending on the kind of a type, certain fields describe information about that type. "\
9
+ "Scalar types provide no information beyond a name and description, while "\
10
+ "Enum types provide their values. Object and Interface types provide the fields "\
11
+ "they describe. Abstract types, Union and Interface, provide the Object types "\
12
+ "possible at runtime. List and NonNull types compose other types."
13
+
14
+ field :kind, GraphQL::Schema::LateBoundType.new("__TypeKind"), null: false
15
+ field :name, String, null: true
16
+ field :description, String, null: true
17
+ field :fields, [GraphQL::Schema::LateBoundType.new("__Field")], null: true do
18
+ argument :include_deprecated, Boolean, required: false, default_value: false
19
+ end
20
+ field :interfaces, [GraphQL::Schema::LateBoundType.new("__Type")], null: true
21
+ field :possible_types, [GraphQL::Schema::LateBoundType.new("__Type")], null: true
22
+ field :enum_values, [GraphQL::Schema::LateBoundType.new("__EnumValue")], null: true do
23
+ argument :include_deprecated, Boolean, required: false, default_value: false
24
+ end
25
+ field :input_fields, [GraphQL::Schema::LateBoundType.new("__InputValue")], null: true
26
+ field :of_type, GraphQL::Schema::LateBoundType.new("__Type"), null: true
27
+ introspection true
28
+
29
+ def kind
30
+ @object.kind.name
31
+ end
32
+
33
+ def enum_values(include_deprecated:)
34
+ if !@object.kind.enum?
35
+ nil
36
+ else
37
+ enum_values = @context.warden.enum_values(@object)
38
+
39
+ if !include_deprecated
40
+ enum_values = enum_values.select {|f| !f.deprecation_reason }
41
+ end
42
+
43
+ enum_values
44
+ end
45
+ end
16
46
 
17
- field :name, types.String
18
- field :description, types.String
19
- field :fields, GraphQL::Introspection::FieldsField
20
- field :interfaces, GraphQL::Introspection::InterfacesField
21
- field :possibleTypes, GraphQL::Introspection::PossibleTypesField
22
- field :enumValues, GraphQL::Introspection::EnumValuesField
23
- field :inputFields, GraphQL::Introspection::InputFieldsField
24
- field :ofType, GraphQL::Introspection::OfTypeField
25
- introspection true
47
+ def interfaces
48
+ if @object.kind == GraphQL::TypeKinds::OBJECT
49
+ @context.warden.interfaces(@object)
50
+ else
51
+ nil
52
+ end
53
+ end
54
+
55
+ def input_fields
56
+ if @object.kind.input_object?
57
+ @context.warden.arguments(@object)
58
+ else
59
+ nil
60
+ end
61
+ end
62
+
63
+ def possible_types
64
+ if @object.kind.resolves?
65
+ @context.warden.possible_types(@object)
66
+ else
67
+ nil
68
+ end
69
+ end
70
+
71
+ def fields(include_deprecated:)
72
+ if !@object.kind.fields?
73
+ nil
74
+ else
75
+ fields = @context.warden.fields(@object)
76
+ if !include_deprecated
77
+ fields = fields.select {|f| !f.deprecation_reason }
78
+ end
79
+ fields.sort_by(&:name)
80
+ end
81
+ end
82
+
83
+ def of_type
84
+ @object.kind.wraps? ? @object.of_type : nil
85
+ end
86
+ end
87
+ end
26
88
  end
@@ -5,6 +5,7 @@ module GraphQL
5
5
  name "__typename"
6
6
  description "The name of this type"
7
7
  type -> { !GraphQL::STRING_TYPE }
8
+ introspection true
8
9
  resolve ->(obj, a, ctx) { ctx.irep_node.owner_type }
9
10
  end
10
11
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ require "graphql/language/printer"
2
3
  require "graphql/language/definition_slice"
3
4
  require "graphql/language/document_from_schema_definition"
4
5
  require "graphql/language/generation"
@@ -6,10 +6,28 @@ module GraphQL
6
6
  # {GraphQL::Language::DocumentFromSchemaDefinition} is used to convert a {GraphQL::Schema} object
7
7
  # To a {GraphQL::Language::Document} AST node.
8
8
  #
9
+ # @param context [Hash]
10
+ # @param only [<#call(member, ctx)>]
11
+ # @param except [<#call(member, ctx)>]
12
+ # @param include_introspection_types [Boolean] Whether or not to include introspection types in the AST
13
+ # @param include_built_in_scalars [Boolean] Whether or not to include built in scalars in the AST
14
+ # @param include_built_in_directives [Boolean] Whether or not to include built in diirectives in the AST
9
15
  class DocumentFromSchemaDefinition
10
- def initialize(schema)
16
+ def initialize(
17
+ schema, context: nil, only: nil, except: nil, include_introspection_types: false,
18
+ include_built_in_directives: false, include_built_in_scalars: false, always_include_schema: false
19
+ )
11
20
  @schema = schema
12
- @types = GraphQL::Schema::Traversal.new(schema, introspection: true).type_map.values
21
+ @always_include_schema = always_include_schema
22
+ @include_introspection_types = include_introspection_types
23
+ @include_built_in_scalars = include_built_in_scalars
24
+ @include_built_in_directives = include_built_in_directives
25
+
26
+ @warden = GraphQL::Schema::Warden.new(
27
+ GraphQL::Filter.new(only: only, except: except),
28
+ schema: @schema,
29
+ context: context,
30
+ )
13
31
  end
14
32
 
15
33
  def document
@@ -18,47 +36,46 @@ module GraphQL
18
36
  )
19
37
  end
20
38
 
21
- protected
22
-
23
- def build_schema_node(schema)
24
- schema_node = GraphQL::Language::Nodes::SchemaDefinition.new(
25
- query: schema.query.name
39
+ def build_schema_node
40
+ GraphQL::Language::Nodes::SchemaDefinition.new(
41
+ query: warden.root_type_for_operation("query"),
42
+ mutation: warden.root_type_for_operation("mutation"),
43
+ subscription: warden.root_type_for_operation("subscription")
26
44
  )
27
-
28
- if schema.mutation
29
- schema_node.mutation = schema.mutation.name
30
- end
31
-
32
- if schema.subscription
33
- schema_node.subscription = schema.subscription.name
34
- end
35
-
36
- schema_node
37
45
  end
38
46
 
39
47
  def build_object_type_node(object_type)
40
48
  GraphQL::Language::Nodes::ObjectTypeDefinition.new(
41
49
  name: object_type.name,
42
- interfaces: object_type.interfaces.map { |iface| build_type_name_node(iface) },
43
- fields: build_field_nodes(object_type.fields.values),
50
+ interfaces: warden.interfaces(object_type).sort_by(&:name).map { |iface| build_type_name_node(iface) },
51
+ fields: build_field_nodes(warden.fields(object_type)),
44
52
  description: object_type.description,
45
53
  )
46
54
  end
47
55
 
48
56
  def build_field_node(field)
49
- GraphQL::Language::Nodes::FieldDefinition.new(
57
+ field_node = GraphQL::Language::Nodes::FieldDefinition.new(
50
58
  name: field.name,
51
- arguments: build_argument_nodes(field.arguments.values),
59
+ arguments: build_argument_nodes(warden.arguments(field)),
52
60
  type: build_type_name_node(field.type),
53
61
  description: field.description,
54
62
  )
63
+
64
+ if field.deprecation_reason
65
+ field_node.directives << GraphQL::Language::Nodes::Directive.new(
66
+ name: GraphQL::Directive::DeprecatedDirective.name,
67
+ arguments: [GraphQL::Language::Nodes::Argument.new(name: "reason", value: field.deprecation_reason)]
68
+ )
69
+ end
70
+
71
+ field_node
55
72
  end
56
73
 
57
74
  def build_union_type_node(union_type)
58
75
  GraphQL::Language::Nodes::UnionTypeDefinition.new(
59
76
  name: union_type.name,
60
77
  description: union_type.description,
61
- types: union_type.possible_types.map { |type| build_type_name_node(type) }
78
+ types: warden.possible_types(union_type).sort_by(&:name).map { |type| build_type_name_node(type) }
62
79
  )
63
80
  end
64
81
 
@@ -66,14 +83,14 @@ module GraphQL
66
83
  GraphQL::Language::Nodes::InterfaceTypeDefinition.new(
67
84
  name: interface_type.name,
68
85
  description: interface_type.description,
69
- fields: build_field_nodes(interface_type.fields.values)
86
+ fields: build_field_nodes(warden.fields(interface_type))
70
87
  )
71
88
  end
72
89
 
73
90
  def build_enum_type_node(enum_type)
74
91
  GraphQL::Language::Nodes::EnumTypeDefinition.new(
75
92
  name: enum_type.name,
76
- values: enum_type.values.values.map do |enum_value|
93
+ values: warden.enum_values(enum_type).sort_by(&:name).map do |enum_value|
77
94
  build_enum_value_node(enum_value)
78
95
  end,
79
96
  description: enum_type.description,
@@ -81,10 +98,19 @@ module GraphQL
81
98
  end
82
99
 
83
100
  def build_enum_value_node(enum_value)
84
- GraphQL::Language::Nodes::EnumValueDefinition.new(
101
+ enum_value_node = GraphQL::Language::Nodes::EnumValueDefinition.new(
85
102
  name: enum_value.name,
86
103
  description: enum_value.description,
87
104
  )
105
+
106
+ if enum_value.deprecation_reason
107
+ enum_value_node.directives << GraphQL::Language::Nodes::Directive.new(
108
+ name: GraphQL::Directive::DeprecatedDirective.name,
109
+ arguments: [GraphQL::Language::Nodes::Argument.new(name: "reason", value: enum_value.deprecation_reason)]
110
+ )
111
+ end
112
+
113
+ enum_value_node
88
114
  end
89
115
 
90
116
  def build_scalar_type_node(scalar_type)
@@ -95,18 +121,23 @@ module GraphQL
95
121
  end
96
122
 
97
123
  def build_argument_node(argument)
98
- GraphQL::Language::Nodes::InputValueDefinition.new(
124
+ argument_node = GraphQL::Language::Nodes::InputValueDefinition.new(
99
125
  name: argument.name,
100
126
  description: argument.description,
101
127
  type: build_type_name_node(argument.type),
102
- default_value: argument.default_value,
103
128
  )
129
+
130
+ if argument.default_value?
131
+ argument_node.default_value = build_default_value(argument.default_value, argument.type)
132
+ end
133
+
134
+ argument_node
104
135
  end
105
136
 
106
137
  def build_input_object_node(input_object)
107
138
  GraphQL::Language::Nodes::InputObjectTypeDefinition.new(
108
139
  name: input_object.name,
109
- fields: build_argument_nodes(input_object.arguments.values),
140
+ fields: build_argument_nodes(warden.arguments(input_object)),
110
141
  description: input_object.description,
111
142
  )
112
143
  end
@@ -114,7 +145,7 @@ module GraphQL
114
145
  def build_directive_node(directive)
115
146
  GraphQL::Language::Nodes::DirectiveDefinition.new(
116
147
  name: directive.name,
117
- arguments: build_argument_nodes(directive.arguments.values),
148
+ arguments: build_argument_nodes(warden.arguments(directive)),
118
149
  locations: directive.locations.map(&:to_s),
119
150
  description: directive.description,
120
151
  )
@@ -135,6 +166,35 @@ module GraphQL
135
166
  end
136
167
  end
137
168
 
169
+ def build_default_value(default_value, type)
170
+ if default_value.nil?
171
+ return GraphQL::Language::Nodes::NullValue.new(name: "null")
172
+ end
173
+
174
+ case type
175
+ when GraphQL::ScalarType
176
+ default_value
177
+ when EnumType
178
+ GraphQL::Language::Nodes::Enum.new(name: type.coerce_isolated_result(default_value))
179
+ when InputObjectType
180
+ GraphQL::Language::Nodes::InputObject.new(
181
+ arguments: default_value.to_h.map do |arg_name, arg_value|
182
+ arg_type = type.input_fields.fetch(arg_name.to_s).type
183
+ GraphQL::Language::Nodes::Argument.new(
184
+ name: arg_name,
185
+ value: build_default_value(arg_value, arg_type)
186
+ )
187
+ end
188
+ )
189
+ when NonNullType
190
+ build_default_value(default_value, type.of_type)
191
+ when ListType
192
+ default_value.to_a.map { |v| build_default_value(v, type.of_type) }
193
+ else
194
+ raise NotImplementedError, "Unexpected default value type #{type.inspect}"
195
+ end
196
+ end
197
+
138
198
  def build_type_definition_node(type)
139
199
  case type
140
200
  when GraphQL::ObjectType
@@ -155,31 +215,63 @@ module GraphQL
155
215
  end
156
216
 
157
217
  def build_argument_nodes(arguments)
158
- arguments.map { |arg| build_argument_node(arg) }
218
+ arguments
219
+ .map { |arg| build_argument_node(arg) }
220
+ .sort_by(&:name)
159
221
  end
160
222
 
161
223
  def build_directive_nodes(directives)
162
- directives.map { |directive| build_directive_node(directive) }
224
+ if !include_built_in_directives
225
+ directives = directives.reject { |directive| directive.default_directive? }
226
+ end
227
+
228
+ directives
229
+ .map { |directive| build_directive_node(directive) }
230
+ .sort_by(&:name)
163
231
  end
164
232
 
165
233
  def build_definition_nodes
166
- definitions = build_type_definition_nodes(types)
167
- definitions += build_directive_nodes(schema.directives.values)
168
- definitions << build_schema_node(schema)
234
+ definitions = []
235
+ definitions << build_schema_node if include_schema_node?
236
+ definitions += build_directive_nodes(warden.directives)
237
+ definitions += build_type_definition_nodes(warden.types)
169
238
  definitions
170
239
  end
171
240
 
172
241
  def build_type_definition_nodes(types)
173
- types.map { |type| build_type_definition_node(type) }
242
+ if !include_introspection_types
243
+ types = types.reject { |type| type.introspection? }
244
+ end
245
+
246
+ if !include_built_in_scalars
247
+ types = types.reject { |type| type.default_scalar? }
248
+ end
249
+
250
+ types
251
+ .map { |type| build_type_definition_node(type) }
252
+ .sort_by(&:name)
174
253
  end
175
254
 
176
255
  def build_field_nodes(fields)
177
- fields.map { |field| build_field_node(field) }
256
+ fields
257
+ .map { |field| build_field_node(field) }
258
+ .sort_by(&:name)
178
259
  end
179
260
 
180
261
  private
181
262
 
182
- attr_reader :schema, :types
263
+ def include_schema_node?
264
+ always_include_schema || !schema_respects_root_name_conventions?(schema)
265
+ end
266
+
267
+ def schema_respects_root_name_conventions?(schema)
268
+ (schema.query.nil? || schema.query.name == 'Query') &&
269
+ (schema.mutation.nil? || schema.mutation.name == 'Mutation') &&
270
+ (schema.subscription.nil? || schema.subscription.name == 'Subscription')
271
+ end
272
+
273
+ attr_reader :schema, :warden, :always_include_schema,
274
+ :include_introspection_types, :include_built_in_directives, :include_built_in_scalars
183
275
  end
184
276
  end
185
277
  end
@@ -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