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.
- checksums.yaml +4 -4
- data/lib/graphql.rb +1 -1
- data/lib/graphql/deprecated_dsl.rb +2 -0
- data/lib/graphql/enum_type.rb +1 -1
- data/lib/graphql/field.rb +10 -1
- data/lib/graphql/input_object_type.rb +3 -1
- data/lib/graphql/introspection.rb +3 -10
- data/lib/graphql/introspection/base_object.rb +15 -0
- data/lib/graphql/introspection/directive_location_enum.rb +11 -7
- data/lib/graphql/introspection/directive_type.rb +23 -16
- data/lib/graphql/introspection/dynamic_fields.rb +11 -0
- data/lib/graphql/introspection/entry_points.rb +29 -0
- data/lib/graphql/introspection/enum_value_type.rb +16 -11
- data/lib/graphql/introspection/field_type.rb +21 -12
- data/lib/graphql/introspection/input_value_type.rb +26 -23
- data/lib/graphql/introspection/schema_field.rb +7 -2
- data/lib/graphql/introspection/schema_type.rb +36 -22
- data/lib/graphql/introspection/type_by_name_field.rb +10 -2
- data/lib/graphql/introspection/type_kind_enum.rb +10 -6
- data/lib/graphql/introspection/type_type.rb +85 -23
- data/lib/graphql/introspection/typename_field.rb +1 -0
- data/lib/graphql/language.rb +1 -0
- data/lib/graphql/language/document_from_schema_definition.rb +129 -37
- data/lib/graphql/language/generation.rb +3 -182
- data/lib/graphql/language/nodes.rb +12 -2
- data/lib/graphql/language/parser.rb +63 -55
- data/lib/graphql/language/parser.y +2 -1
- data/lib/graphql/language/printer.rb +351 -0
- data/lib/graphql/object_type.rb +1 -1
- data/lib/graphql/query.rb +1 -1
- data/lib/graphql/query/arguments.rb +24 -8
- data/lib/graphql/query/context.rb +3 -0
- data/lib/graphql/query/literal_input.rb +4 -1
- data/lib/graphql/railtie.rb +28 -6
- data/lib/graphql/schema.rb +42 -7
- data/lib/graphql/schema/enum.rb +1 -0
- data/lib/graphql/schema/field.rb +26 -5
- data/lib/graphql/schema/field/dynamic_resolve.rb +18 -9
- data/lib/graphql/schema/input_object.rb +2 -2
- data/lib/graphql/schema/introspection_system.rb +93 -0
- data/lib/graphql/schema/late_bound_type.rb +32 -0
- data/lib/graphql/schema/member.rb +21 -1
- data/lib/graphql/schema/member/build_type.rb +8 -6
- data/lib/graphql/schema/member/has_fields.rb +1 -1
- data/lib/graphql/schema/member/instrumentation.rb +3 -1
- data/lib/graphql/schema/member/list_type_proxy.rb +4 -0
- data/lib/graphql/schema/member/non_null_type_proxy.rb +4 -0
- data/lib/graphql/schema/object.rb +2 -1
- data/lib/graphql/schema/printer.rb +33 -266
- data/lib/graphql/schema/traversal.rb +74 -6
- data/lib/graphql/schema/validation.rb +3 -2
- data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +6 -6
- data/lib/graphql/tracing/scout_tracing.rb +2 -2
- data/lib/graphql/upgrader/member.rb +463 -63
- data/lib/graphql/version.rb +1 -1
- data/spec/fixtures/upgrader/blame_range.original.rb +43 -0
- data/spec/fixtures/upgrader/blame_range.transformed.rb +31 -0
- data/spec/fixtures/upgrader/subscribable.original.rb +51 -0
- data/spec/fixtures/upgrader/subscribable.transformed.rb +46 -0
- data/spec/fixtures/upgrader/type_x.original.rb +35 -0
- data/spec/fixtures/upgrader/type_x.transformed.rb +35 -0
- data/spec/graphql/language/document_from_schema_definition_spec.rb +729 -296
- data/spec/graphql/language/generation_spec.rb +21 -186
- data/spec/graphql/language/nodes_spec.rb +21 -0
- data/spec/graphql/language/printer_spec.rb +203 -0
- data/spec/graphql/query/arguments_spec.rb +14 -4
- data/spec/graphql/query/context_spec.rb +17 -0
- data/spec/graphql/schema/build_from_definition_spec.rb +13 -4
- data/spec/graphql/schema/field_spec.rb +14 -0
- data/spec/graphql/schema/introspection_system_spec.rb +39 -0
- data/spec/graphql/schema/object_spec.rb +12 -1
- data/spec/graphql/schema/printer_spec.rb +14 -14
- data/spec/graphql/tracing/platform_tracing_spec.rb +2 -2
- data/spec/graphql/upgrader/member_spec.rb +274 -62
- data/spec/support/jazz.rb +75 -3
- metadata +38 -9
- data/lib/graphql/introspection/arguments_field.rb +0 -7
- data/lib/graphql/introspection/enum_values_field.rb +0 -18
- data/lib/graphql/introspection/fields_field.rb +0 -13
- data/lib/graphql/introspection/input_fields_field.rb +0 -12
- data/lib/graphql/introspection/interfaces_field.rb +0 -11
- data/lib/graphql/introspection/of_type_field.rb +0 -6
- 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
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
data/lib/graphql/language.rb
CHANGED
@@ -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(
|
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
|
-
@
|
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
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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:
|
43
|
-
fields: build_field_nodes(
|
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(
|
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:
|
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(
|
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.
|
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(
|
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(
|
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
|
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
|
-
|
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 =
|
167
|
-
definitions
|
168
|
-
definitions
|
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
|
-
|
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
|
256
|
+
fields
|
257
|
+
.map { |field| build_field_node(field) }
|
258
|
+
.sort_by(&:name)
|
178
259
|
end
|
179
260
|
|
180
261
|
private
|
181
262
|
|
182
|
-
|
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
|
-
|
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
|