graphql 1.8.0.pre2 → 1.8.0.pre3

Sign up to get free protection for your applications and to get access to all the features.
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,8 +4,8 @@ module GraphQL
4
4
  class InputObject < GraphQL::Schema::Member
5
5
  extend GraphQL::Delegate
6
6
 
7
- def initialize(values, context:)
8
- @arguments = self.class.arguments_class.new(values, context: context)
7
+ def initialize(values, context:, defaults_used:)
8
+ @arguments = self.class.arguments_class.new(values, context: context, defaults_used: defaults_used)
9
9
  @context = context
10
10
  end
11
11
 
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ class IntrospectionSystem
5
+ attr_reader :schema_type, :type_type, :typename_field
6
+
7
+ def initialize(schema)
8
+ @schema = schema
9
+ @built_in_namespace = GraphQL::Introspection
10
+ @custom_namespace = schema.introspection_namespace || @built_in_namespace
11
+
12
+ # Use to-graphql to avoid sharing with any previous instantiations
13
+ @schema_type = load_constant(:SchemaType).to_graphql
14
+ @type_type = load_constant(:TypeType).to_graphql
15
+ @field_type = load_constant(:FieldType).to_graphql
16
+ @directive_type = load_constant(:DirectiveType).to_graphql
17
+ @enum_value_type = load_constant(:EnumValueType).to_graphql
18
+ @input_value_type = load_constant(:InputValueType).to_graphql
19
+ @type_kind_enum = load_constant(:TypeKindEnum).to_graphql
20
+ @directive_location_enum = load_constant(:DirectiveLocationEnum).to_graphql
21
+ @entry_point_fields = get_fields_from_class(class_sym: :EntryPoints)
22
+ @dynamic_fields = get_fields_from_class(class_sym: :DynamicFields)
23
+ end
24
+
25
+ def object_types
26
+ [
27
+ @schema_type,
28
+ @type_type,
29
+ @field_type,
30
+ @directive_type,
31
+ @enum_value_type,
32
+ @input_value_type,
33
+ @type_kind_enum,
34
+ @directive_location_enum,
35
+ ]
36
+ end
37
+
38
+ def entry_points
39
+ @entry_point_fields.values
40
+ end
41
+
42
+ def entry_point(name:)
43
+ @entry_point_fields[name]
44
+ end
45
+
46
+ def dynamic_fields
47
+ @dynamic_fields.values
48
+ end
49
+
50
+ def dynamic_field(name:)
51
+ @dynamic_fields[name]
52
+ end
53
+
54
+ private
55
+
56
+ def load_constant(class_name)
57
+ @custom_namespace.const_get(class_name)
58
+ rescue NameError
59
+ # Dup the built-in so that the cached fields aren't shared
60
+ @built_in_namespace.const_get(class_name)
61
+ end
62
+
63
+ def get_fields_from_class(class_sym:)
64
+ object_class = load_constant(class_sym)
65
+ object_type_defn = object_class.to_graphql
66
+ extracted_field_defns = {}
67
+ object_type_defn.all_fields.each do |field_defn|
68
+ inner_resolve = field_defn.resolve_proc
69
+ resolve_with_instantiate = PerFieldProxyResolve.new(object_class: object_class, inner_resolve: inner_resolve)
70
+ extracted_field_defns[field_defn.name] = field_defn.redefine(resolve: resolve_with_instantiate)
71
+ end
72
+ extracted_field_defns
73
+ end
74
+
75
+ class PerFieldProxyResolve
76
+ def initialize(object_class:, inner_resolve:)
77
+ @object_class = object_class
78
+ @inner_resolve = inner_resolve
79
+ end
80
+
81
+ def call(obj, args, ctx)
82
+ query_ctx = ctx.query.context
83
+ # Remove the QueryType wrapper
84
+ if obj.is_a?(GraphQL::Schema::Object)
85
+ obj = obj.object
86
+ end
87
+ wrapped_object = @object_class.new(obj, query_ctx)
88
+ @inner_resolve.call(wrapped_object, args, ctx)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ class Schema
4
+ # A stand-in for a type which will be resolved in a given schema, by name.
5
+ # TODO: support argument types too, make this a public API somehow
6
+ # @api Private
7
+ class LateBoundType
8
+ attr_reader :name
9
+ def initialize(local_name)
10
+ @name = local_name
11
+ end
12
+
13
+ def unwrap
14
+ self
15
+ end
16
+
17
+ def to_non_null_type
18
+ GraphQL::NonNullType.new(of_type: self)
19
+ end
20
+
21
+ def to_list_type
22
+ GraphQL::ListType.new(of_type: self)
23
+ end
24
+
25
+ def inspect
26
+ "#<LateBoundType @name=#{name}>"
27
+ end
28
+
29
+ alias :to_s :inspect
30
+ end
31
+ end
32
+ end
@@ -15,6 +15,11 @@ module GraphQL
15
15
  def graphql_definition
16
16
  @graphql_definition ||= to_graphql
17
17
  end
18
+
19
+ def initialize_copy(original)
20
+ super
21
+ @graphql_definition = nil
22
+ end
18
23
  end
19
24
 
20
25
  # These constants are interpreted as GraphQL types
@@ -58,7 +63,7 @@ module GraphQL
58
63
  if new_name
59
64
  @graphql_name = new_name
60
65
  else
61
- @graphql_name || self.name.split("::").last.sub(/Type\Z/, "")
66
+ overridden_graphql_name || self.name.split("::").last.sub(/Type\Z/, "")
62
67
  end
63
68
  end
64
69
 
@@ -84,6 +89,15 @@ module GraphQL
84
89
  end
85
90
  end
86
91
 
92
+ # @return [Boolean] If true, this object is part of the introspection system
93
+ def introspection(new_introspection = nil)
94
+ if !new_introspection.nil?
95
+ @introspection = new_introspection
96
+ else
97
+ @introspection || (superclass <= Schema::Member ? superclass.introspection : false)
98
+ end
99
+ end
100
+
87
101
  def to_graphql
88
102
  raise NotImplementedError
89
103
  end
@@ -95,6 +109,12 @@ module GraphQL
95
109
  def to_non_null_type
96
110
  NonNullTypeProxy.new(self)
97
111
  end
112
+
113
+ protected
114
+
115
+ def overridden_graphql_name
116
+ @graphql_name || (superclass <= GraphQL::Schema::Member ? superclass.overridden_graphql_name : nil)
117
+ end
98
118
  end
99
119
  end
100
120
  end
@@ -43,7 +43,7 @@ module GraphQL
43
43
  end
44
44
  end
45
45
  end
46
- when GraphQL::BaseType
46
+ when GraphQL::BaseType, GraphQL::Schema::LateBoundType
47
47
  type_expr
48
48
  when Array
49
49
  if type_expr.length != 1
@@ -77,7 +77,7 @@ module GraphQL
77
77
 
78
78
  def to_type_name(something)
79
79
  case something
80
- when GraphQL::BaseType
80
+ when GraphQL::BaseType, GraphQL::Schema::LateBoundType
81
81
  something.unwrap.name
82
82
  when Array
83
83
  to_type_name(something.first)
@@ -95,11 +95,13 @@ module GraphQL
95
95
  end
96
96
 
97
97
  def camelize(string)
98
- return string unless string.include?('_')
99
-
100
- string.split('_').map(&:capitalize).join.tap do |camelized|
101
- camelized[0] = camelized[0].downcase
98
+ return string unless string.include?("_")
99
+ camelized = string.split('_').map(&:capitalize).join
100
+ camelized[0] = camelized[0].downcase
101
+ if string.start_with?("__")
102
+ camelized = "__#{camelized}"
102
103
  end
104
+ camelized
103
105
  end
104
106
 
105
107
  def underscore(string)
@@ -30,7 +30,7 @@ module GraphQL
30
30
  # @param field_defn [GraphQL::Schema::Field]
31
31
  # @return [void]
32
32
  def add_field(field_defn)
33
- fields.reject! {|f| f.name == field_defn.name}
33
+ own_fields.reject! {|f| f.name == field_defn.name}
34
34
  own_fields << field_defn
35
35
  nil
36
36
  end
@@ -100,7 +100,9 @@ module GraphQL
100
100
  end
101
101
 
102
102
  if concrete_type && (object_class = concrete_type.metadata[:object_class])
103
- object_class.new(obj, ctx)
103
+ # use the query-level context here, since it won't be field-specific anyways
104
+ query_ctx = ctx.query.context
105
+ object_class.new(obj, query_ctx)
104
106
  else
105
107
  obj
106
108
  end
@@ -15,6 +15,10 @@ module GraphQL
15
15
  def to_graphql
16
16
  @member.graphql_definition.to_list_type
17
17
  end
18
+
19
+ def to_non_null_type
20
+ NonNullTypeProxy.new(self)
21
+ end
18
22
  end
19
23
  end
20
24
  end
@@ -15,6 +15,10 @@ module GraphQL
15
15
  def to_graphql
16
16
  @member.graphql_definition.to_non_null_type
17
17
  end
18
+
19
+ def to_list_type
20
+ ListTypeProxy.new(self)
21
+ end
18
22
  end
19
23
  end
20
24
  end
@@ -45,9 +45,10 @@ module GraphQL
45
45
  obj_type.name = graphql_name
46
46
  obj_type.description = description
47
47
  obj_type.interfaces = interfaces
48
+ obj_type.introspection = introspection
48
49
 
49
50
  fields.each do |field_inst|
50
- field_defn = field_inst.graphql_definition
51
+ field_defn = field_inst.to_graphql
51
52
  obj_type.fields[field_defn.name] = field_defn
52
53
  end
53
54
 
@@ -36,7 +36,7 @@ module GraphQL
36
36
  # printer = GraphQL::Schema::Printer.new(MySchema)
37
37
  # puts printer.print_type(post_type)
38
38
  #
39
- class Printer
39
+ class Printer < GraphQL::Language::Printer
40
40
  attr_reader :schema, :warden
41
41
 
42
42
  # @param schema [GraphQL::Schema]
@@ -45,21 +45,32 @@ module GraphQL
45
45
  # @param except [<#call(member, ctx)>]
46
46
  # @param introspection [Boolean] Should include the introspection types in the string?
47
47
  def initialize(schema, context: nil, only: nil, except: nil, introspection: false)
48
- @schema = schema
49
- @context = context
48
+ @document_from_schema = GraphQL::Language::DocumentFromSchemaDefinition.new(
49
+ schema,
50
+ context: context,
51
+ only: only,
52
+ except: except,
53
+ include_introspection_types: introspection,
54
+ )
55
+
56
+ @document = @document_from_schema.document
50
57
 
51
- blacklist = build_blacklist(only, except, introspection: introspection)
52
- filter = GraphQL::Filter.new(except: blacklist)
53
- @warden = GraphQL::Schema::Warden.new(filter, schema: @schema, context: @context)
58
+ @schema = schema
54
59
  end
55
60
 
56
61
  # Return the GraphQL schema string for the introspection type system
57
62
  def self.print_introspection_schema
58
63
  query_root = ObjectType.define(name: "Root")
59
64
  schema = GraphQL::Schema.define(query: query_root)
60
- blacklist = ->(m, ctx) { m == query_root }
61
- printer = new(schema, except: blacklist, introspection: true)
62
- printer.print_schema
65
+
66
+ introspection_schema_ast = GraphQL::Language::DocumentFromSchemaDefinition.new(
67
+ schema,
68
+ except: ->(member, _) { member.name == "Root" },
69
+ include_introspection_types: true,
70
+ include_built_in_directives: true,
71
+ ).document
72
+
73
+ introspection_schema_ast.to_query_string(printer: IntrospectionPrinter.new)
63
74
  end
64
75
 
65
76
  # Return a GraphQL schema string for the defined types in the schema
@@ -74,277 +85,33 @@ module GraphQL
74
85
 
75
86
  # Return a GraphQL schema string for the defined types in the schema
76
87
  def print_schema
77
- directive_definitions = warden.directives.map { |directive| print_directive(directive) }
78
-
79
- printable_types = warden.types.reject(&:default_scalar?)
80
-
81
- type_definitions = printable_types
82
- .sort_by(&:name)
83
- .map { |type| print_type(type) }
84
-
85
- [print_schema_definition].compact
86
- .concat(directive_definitions)
87
- .concat(type_definitions).join("\n\n")
88
+ print(@document)
88
89
  end
89
90
 
90
91
  def print_type(type)
91
- TypeKindPrinters::STRATEGIES.fetch(type.kind).print(warden, type)
92
+ node = @document_from_schema.build_object_type_node(type)
93
+ print(node)
92
94
  end
93
95
 
94
- private
95
-
96
- # By default, these are included in a schema printout
97
- IS_USER_DEFINED_MEMBER = ->(member) {
98
- case member
99
- when GraphQL::BaseType
100
- !member.introspection?
101
- when GraphQL::Directive
102
- !member.default_directive?
103
- else
104
- true
105
- end
106
- }
107
-
108
- private_constant :IS_USER_DEFINED_MEMBER
96
+ def print_directive(directive)
97
+ if directive.name == "deprecated"
98
+ reason = directive.arguments.find { |arg| arg.name == "reason" }
109
99
 
110
- def build_blacklist(only, except, introspection:)
111
- if introspection
112
- if only
113
- ->(m, ctx) { !only.call(m, ctx) }
114
- elsif except
115
- except
100
+ if reason.value == GraphQL::Directive::DEFAULT_DEPRECATION_REASON
101
+ "@deprecated"
116
102
  else
117
- ->(m, ctx) { false }
103
+ "@deprecated(reason: \"#{reason.value}\")"
118
104
  end
119
105
  else
120
- if only
121
- ->(m, ctx) { !(IS_USER_DEFINED_MEMBER.call(m) && only.call(m, ctx)) }
122
- elsif except
123
- ->(m, ctx) { !IS_USER_DEFINED_MEMBER.call(m) || except.call(m, ctx) }
124
- else
125
- ->(m, ctx) { !IS_USER_DEFINED_MEMBER.call(m) }
126
- end
106
+ super
127
107
  end
128
108
  end
129
109
 
130
- def print_schema_definition
131
- if (schema.query.nil? || schema.query.name == 'Query') &&
132
- (schema.mutation.nil? || schema.mutation.name == 'Mutation') &&
133
- (schema.subscription.nil? || schema.subscription.name == 'Subscription')
134
- return
110
+ class IntrospectionPrinter < GraphQL::Language::Printer
111
+ def print_schema_definition(schema)
112
+ "schema {\n query: Root\n}"
135
113
  end
136
-
137
- operations = [:query, :mutation, :subscription].map do |operation_type|
138
- object_type = schema.public_send(operation_type)
139
- # Special treatment for the introspection schema, which prints `{ query: "Root" }`
140
- if object_type && (warden.get_type(object_type.name) || (object_type.name == "Root" && schema.query == object_type))
141
- " #{operation_type}: #{object_type.name}\n"
142
- else
143
- nil
144
- end
145
- end.compact.join
146
- "schema {\n#{operations}}"
147
- end
148
-
149
- def print_directive(directive)
150
- TypeKindPrinters::DirectivePrinter.print(warden, directive)
151
- end
152
-
153
- module TypeKindPrinters
154
- module DeprecatedPrinter
155
- def print_deprecated(field_or_enum_value)
156
- return unless field_or_enum_value.deprecation_reason
157
-
158
- case field_or_enum_value.deprecation_reason
159
- when nil
160
- ''
161
- when '', GraphQL::Directive::DEFAULT_DEPRECATION_REASON
162
- ' @deprecated'
163
- else
164
- " @deprecated(reason: #{field_or_enum_value.deprecation_reason.to_s.inspect})"
165
- end
166
- end
167
- end
168
-
169
- module DescriptionPrinter
170
- def print_description(definition, indentation='', first_in_block=true)
171
- return '' unless definition.description
172
-
173
- description = indentation != '' && !first_in_block ? "\n".dup : "".dup
174
- description << GraphQL::Language::Comments.commentize(definition.description, indent: indentation)
175
- end
176
- end
177
-
178
- module ArgsPrinter
179
- include DescriptionPrinter
180
- def print_args(warden, field, indentation = '')
181
- arguments = warden.arguments(field)
182
- return if arguments.empty?
183
-
184
- if arguments.all?{ |arg| !arg.description }
185
- return "(#{arguments.map{ |arg| print_input_value(arg) }.join(", ")})"
186
- end
187
-
188
- out = "(\n".dup
189
- out << arguments.sort_by(&:name).map.with_index{ |arg, i|
190
- "#{print_description(arg, " #{indentation}", i == 0)} #{indentation}"\
191
- "#{print_input_value(arg)}"
192
- }.join("\n")
193
- out << "\n#{indentation})"
194
- end
195
-
196
- def print_input_value(arg)
197
- if arg.default_value?
198
- default_string = " = #{print_value(arg.default_value, arg.type)}"
199
- else
200
- default_string = nil
201
- end
202
-
203
- "#{arg.name}: #{arg.type.to_s}#{default_string}"
204
- end
205
-
206
- def print_value(value, type)
207
- case type
208
- when FLOAT_TYPE
209
- return 'null' if value.nil?
210
- value.to_f.inspect
211
- when INT_TYPE
212
- return 'null' if value.nil?
213
- value.to_i.inspect
214
- when BOOLEAN_TYPE
215
- return 'null' if value.nil?
216
- (!!value).inspect
217
- when ScalarType, ID_TYPE, STRING_TYPE
218
- return 'null' if value.nil?
219
- value.to_s.inspect
220
- when EnumType
221
- return 'null' if value.nil?
222
- type.coerce_isolated_result(value)
223
- when InputObjectType
224
- return 'null' if value.nil?
225
- fields = value.to_h.map{ |field_name, field_value|
226
- field_type = type.input_fields.fetch(field_name.to_s).type
227
- "#{field_name}: #{print_value(field_value, field_type)}"
228
- }.join(", ")
229
- "{#{fields}}"
230
- when NonNullType
231
- print_value(value, type.of_type)
232
- when ListType
233
- return 'null' if value.nil?
234
- "[#{value.to_a.map{ |v| print_value(v, type.of_type) }.join(", ")}]"
235
- else
236
- raise NotImplementedError, "Unexpected value type #{type.inspect}"
237
- end
238
- end
239
- end
240
-
241
- module FieldPrinter
242
- include DeprecatedPrinter
243
- include ArgsPrinter
244
- include DescriptionPrinter
245
- def print_fields(warden, type)
246
- fields = warden.fields(type)
247
- fields.sort_by(&:name).map.with_index { |field, i|
248
- "#{print_description(field, ' ', i == 0)}"\
249
- " #{field.name}#{print_args(warden, field, ' ')}: #{field.type}#{print_deprecated(field)}"
250
- }.join("\n")
251
- end
252
- end
253
-
254
- class DirectivePrinter
255
- extend ArgsPrinter
256
- extend DescriptionPrinter
257
- def self.print(warden, directive)
258
- "#{print_description(directive)}"\
259
- "directive @#{directive.name}#{print_args(warden, directive)} "\
260
- "on #{directive.locations.join(' | ')}"
261
- end
262
- end
263
-
264
- class ScalarPrinter
265
- extend DescriptionPrinter
266
- def self.print(warden, type)
267
- "#{print_description(type)}"\
268
- "scalar #{type.name}"
269
- end
270
- end
271
-
272
- class ObjectPrinter
273
- extend FieldPrinter
274
- extend DescriptionPrinter
275
- def self.print(warden, type)
276
- interfaces = warden.interfaces(type)
277
- if interfaces.any?
278
- implementations = " implements #{interfaces.sort_by(&:name).map(&:to_s).join(", ")}"
279
- else
280
- implementations = nil
281
- end
282
-
283
- "#{print_description(type)}"\
284
- "type #{type.name}#{implementations} {\n"\
285
- "#{print_fields(warden, type)}\n"\
286
- "}"
287
- end
288
- end
289
-
290
- class InterfacePrinter
291
- extend FieldPrinter
292
- extend DescriptionPrinter
293
- def self.print(warden, type)
294
- "#{print_description(type)}"\
295
- "interface #{type.name} {\n#{print_fields(warden, type)}\n}"
296
- end
297
- end
298
-
299
- class UnionPrinter
300
- extend DescriptionPrinter
301
- def self.print(warden, type)
302
- possible_types = warden.possible_types(type)
303
- "#{print_description(type)}"\
304
- "union #{type.name} = #{possible_types.sort_by(&:name).map(&:to_s).join(" | ")}"
305
- end
306
- end
307
-
308
- class EnumPrinter
309
- extend DeprecatedPrinter
310
- extend DescriptionPrinter
311
- def self.print(warden, type)
312
- enum_values = warden.enum_values(type)
313
-
314
- values = enum_values.sort_by(&:name).map.with_index { |v, i|
315
- "#{print_description(v, ' ', i == 0)}"\
316
- " #{v.name}#{print_deprecated(v)}"
317
- }.join("\n")
318
-
319
- "#{print_description(type)}"\
320
- "enum #{type.name} {\n#{values}\n}"
321
- end
322
- end
323
-
324
- class InputObjectPrinter
325
- extend FieldPrinter
326
- extend DescriptionPrinter
327
- def self.print(warden, type)
328
- arguments = warden.arguments(type)
329
- fields = arguments.sort_by(&:name).map.with_index{ |field, i|
330
- "#{print_description(field, " ", i == 0)}"\
331
- " #{print_input_value(field)}"
332
- }.join("\n")
333
- "#{print_description(type)}"\
334
- "input #{type.name} {\n#{fields}\n}"
335
- end
336
- end
337
-
338
- STRATEGIES = {
339
- GraphQL::TypeKinds::SCALAR => ScalarPrinter,
340
- GraphQL::TypeKinds::OBJECT => ObjectPrinter,
341
- GraphQL::TypeKinds::INTERFACE => InterfacePrinter,
342
- GraphQL::TypeKinds::UNION => UnionPrinter,
343
- GraphQL::TypeKinds::ENUM => EnumPrinter,
344
- GraphQL::TypeKinds::INPUT_OBJECT => InputObjectPrinter,
345
- }
346
114
  end
347
- private_constant :TypeKindPrinters
348
115
  end
349
116
  end
350
117
  end