graphql 2.3.14 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/graphql/orm_mutations_base.rb +1 -1
  3. data/lib/generators/graphql/templates/base_resolver.erb +2 -0
  4. data/lib/generators/graphql/type_generator.rb +1 -1
  5. data/lib/graphql/analysis.rb +1 -1
  6. data/lib/graphql/dataloader/async_dataloader.rb +3 -2
  7. data/lib/graphql/dataloader/source.rb +1 -1
  8. data/lib/graphql/dataloader.rb +31 -10
  9. data/lib/graphql/execution/interpreter/resolve.rb +10 -6
  10. data/lib/graphql/invalid_null_error.rb +1 -1
  11. data/lib/graphql/language/comment.rb +18 -0
  12. data/lib/graphql/language/document_from_schema_definition.rb +38 -4
  13. data/lib/graphql/language/lexer.rb +15 -12
  14. data/lib/graphql/language/nodes.rb +22 -14
  15. data/lib/graphql/language/parser.rb +5 -0
  16. data/lib/graphql/language/printer.rb +23 -7
  17. data/lib/graphql/language.rb +6 -5
  18. data/lib/graphql/query/null_context.rb +1 -1
  19. data/lib/graphql/query.rb +49 -16
  20. data/lib/graphql/rubocop/graphql/field_type_in_block.rb +23 -8
  21. data/lib/graphql/schema/always_visible.rb +6 -3
  22. data/lib/graphql/schema/argument.rb +14 -1
  23. data/lib/graphql/schema/build_from_definition.rb +1 -0
  24. data/lib/graphql/schema/enum.rb +3 -0
  25. data/lib/graphql/schema/enum_value.rb +9 -1
  26. data/lib/graphql/schema/field.rb +35 -14
  27. data/lib/graphql/schema/input_object.rb +20 -7
  28. data/lib/graphql/schema/interface.rb +1 -0
  29. data/lib/graphql/schema/member/base_dsl_methods.rb +15 -0
  30. data/lib/graphql/schema/member/has_arguments.rb +2 -2
  31. data/lib/graphql/schema/member/has_fields.rb +2 -2
  32. data/lib/graphql/schema/printer.rb +1 -0
  33. data/lib/graphql/schema/resolver.rb +3 -4
  34. data/lib/graphql/schema/validator/required_validator.rb +28 -4
  35. data/lib/graphql/schema/visibility/migration.rb +186 -0
  36. data/lib/graphql/schema/visibility/profile.rb +523 -0
  37. data/lib/graphql/schema/visibility.rb +75 -0
  38. data/lib/graphql/schema/warden.rb +77 -15
  39. data/lib/graphql/schema.rb +203 -61
  40. data/lib/graphql/static_validation/rules/arguments_are_defined.rb +2 -1
  41. data/lib/graphql/static_validation/rules/directives_are_defined.rb +2 -1
  42. data/lib/graphql/static_validation/rules/directives_are_in_valid_locations.rb +2 -0
  43. data/lib/graphql/static_validation/rules/fields_are_defined_on_type.rb +2 -1
  44. data/lib/graphql/static_validation/rules/fields_will_merge.rb +1 -0
  45. data/lib/graphql/static_validation/rules/fragment_types_exist.rb +11 -1
  46. data/lib/graphql/static_validation/rules/variables_are_input_types.rb +10 -1
  47. data/lib/graphql/static_validation/validation_context.rb +15 -0
  48. data/lib/graphql/subscriptions/action_cable_subscriptions.rb +2 -1
  49. data/lib/graphql/subscriptions.rb +3 -1
  50. data/lib/graphql/testing/helpers.rb +2 -1
  51. data/lib/graphql/tracing/notifications_trace.rb +2 -2
  52. data/lib/graphql/version.rb +1 -1
  53. metadata +11 -9
  54. data/lib/graphql/schema/subset.rb +0 -509
  55. data/lib/graphql/schema/types_migration.rb +0 -187
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a0c7d49f75d9f1740b415ca0c088733fa4ddf380da43dcd469d20654d89ad93
4
- data.tar.gz: 0bf6ad1c22adc0a8d9e948287a751a561fb7203ca02cb902341b13ad3df40db1
3
+ metadata.gz: 26e43b0bc48317698ed17f8a11498c19a7a4a0df9d33fdc9785edc47ae1147b6
4
+ data.tar.gz: 74402e930ebe03a451bc2bdb82285642aeeba7222ab491dd9329400fc852eb41
5
5
  SHA512:
6
- metadata.gz: 73583aaf16bda54678168edf89e471ee1b3b54d7a2f1aa1bc0c9b959113000768a8d12a8f3ffeec29561639917fcb694ec2fd8c25f22dd8eaf33c46133f40160
7
- data.tar.gz: 615f46f473d89526106f9d85d3560052dacfd35f5f31119a037fa2b1fda8f92445bd15c5993df3ebce8af10df9907a2d41576cc4444822df0606a13b0d9ed7c9
6
+ metadata.gz: f1d97c4397ca8410f6b62c3ea2de9a0a4b18ca610adcb92de9676c5377b00a071cbff4fbd0396760eea9ab359e4b0b8cdfff1630c9fa83de51cfd31b0b96307f
7
+ data.tar.gz: d9250a9ad1d57f40e7b0151484f77a66e11a361f8b0f50938f42219eb8322a9b4dc59c59102f4b49f62a28e90f03b8f9e0cf5b2799b5fd5080dbcf443cebac15
@@ -18,7 +18,7 @@ module Graphql
18
18
  class_option :orm, banner: "NAME", type: :string, required: true,
19
19
  desc: "ORM to generate the controller for"
20
20
 
21
- class_option 'namespaced_types',
21
+ class_option :namespaced_types,
22
22
  type: :boolean,
23
23
  required: false,
24
24
  default: false,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  <% module_namespacing_when_supported do -%>
2
4
  module Resolvers
3
5
  class BaseResolver < GraphQL::Schema::Resolver
@@ -11,7 +11,7 @@ module Graphql
11
11
  class TypeGeneratorBase < Rails::Generators::NamedBase
12
12
  include Core
13
13
 
14
- class_option 'namespaced_types',
14
+ class_option :namespaced_types,
15
15
  type: :boolean,
16
16
  required: false,
17
17
  default: false,
@@ -81,7 +81,7 @@ module GraphQL
81
81
  end
82
82
  rescue Timeout::Error
83
83
  [GraphQL::AnalysisError.new("Timeout on validation of query")]
84
- rescue GraphQL::UnauthorizedError
84
+ rescue GraphQL::UnauthorizedError, GraphQL::ExecutionError
85
85
  # This error was raised during analysis and will be returned the client before execution
86
86
  []
87
87
  end
@@ -12,6 +12,7 @@ module GraphQL
12
12
  end
13
13
 
14
14
  def run
15
+ jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
15
16
  job_fibers = []
16
17
  next_job_fibers = []
17
18
  source_tasks = []
@@ -23,7 +24,7 @@ module GraphQL
23
24
  first_pass = false
24
25
  fiber_vars = get_fiber_variables
25
26
 
26
- while (f = (job_fibers.shift || spawn_job_fiber))
27
+ while (f = (job_fibers.shift || (((job_fibers.size + next_job_fibers.size + source_tasks.size) < jobs_fiber_limit) && spawn_job_fiber)))
27
28
  if f.alive?
28
29
  finished = run_fiber(f)
29
30
  if !finished
@@ -37,7 +38,7 @@ module GraphQL
37
38
  Sync do |root_task|
38
39
  set_fiber_variables(fiber_vars)
39
40
  while source_tasks.any? || @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) }
40
- while (task = source_tasks.shift || spawn_source_task(root_task, sources_condition))
41
+ while (task = (source_tasks.shift || (((job_fibers.size + next_job_fibers.size + source_tasks.size + next_source_tasks.size) < total_fiber_limit) && spawn_source_task(root_task, sources_condition))))
41
42
  if task.alive?
42
43
  root_task.yield # give the source task a chance to run
43
44
  next_source_tasks << task
@@ -98,7 +98,7 @@ module GraphQL
98
98
  while pending_result_keys.any? { |key| !@results.key?(key) }
99
99
  iterations += 1
100
100
  if iterations > MAX_ITERATIONS
101
- raise "#{self.class}#sync tried #{MAX_ITERATIONS} times to load pending keys (#{pending_result_keys}), but they still weren't loaded. There is likely a circular dependency."
101
+ raise "#{self.class}#sync tried #{MAX_ITERATIONS} times to load pending keys (#{pending_result_keys}), but they still weren't loaded. There is likely a circular dependency#{@dataloader.fiber_limit ? " or `fiber_limit: #{@dataloader.fiber_limit}` is set too low" : ""}."
102
102
  end
103
103
  @dataloader.yield
104
104
  end
@@ -24,18 +24,23 @@ module GraphQL
24
24
  #
25
25
  class Dataloader
26
26
  class << self
27
- attr_accessor :default_nonblocking
27
+ attr_accessor :default_nonblocking, :default_fiber_limit
28
28
  end
29
29
 
30
- NonblockingDataloader = Class.new(self) { self.default_nonblocking = true }
31
-
32
- def self.use(schema, nonblocking: nil)
33
- schema.dataloader_class = if nonblocking
30
+ def self.use(schema, nonblocking: nil, fiber_limit: nil)
31
+ dataloader_class = if nonblocking
34
32
  warn("`nonblocking: true` is deprecated from `GraphQL::Dataloader`, please use `GraphQL::Dataloader::AsyncDataloader` instead. Docs: https://graphql-ruby.org/dataloader/async_dataloader.")
35
- NonblockingDataloader
33
+ Class.new(self) { self.default_nonblocking = true }
36
34
  else
37
35
  self
38
36
  end
37
+
38
+ if fiber_limit
39
+ dataloader_class = Class.new(dataloader_class)
40
+ dataloader_class.default_fiber_limit = fiber_limit
41
+ end
42
+
43
+ schema.dataloader_class = dataloader_class
39
44
  end
40
45
 
41
46
  # Call the block with a Dataloader instance,
@@ -50,14 +55,18 @@ module GraphQL
50
55
  result
51
56
  end
52
57
 
53
- def initialize(nonblocking: self.class.default_nonblocking)
58
+ def initialize(nonblocking: self.class.default_nonblocking, fiber_limit: self.class.default_fiber_limit)
54
59
  @source_cache = Hash.new { |h, k| h[k] = {} }
55
60
  @pending_jobs = []
56
61
  if !nonblocking.nil?
57
62
  @nonblocking = nonblocking
58
63
  end
64
+ @fiber_limit = fiber_limit
59
65
  end
60
66
 
67
+ # @return [Integer, nil]
68
+ attr_reader :fiber_limit
69
+
61
70
  def nonblocking?
62
71
  @nonblocking
63
72
  end
@@ -178,6 +187,7 @@ module GraphQL
178
187
  end
179
188
 
180
189
  def run
190
+ jobs_fiber_limit, total_fiber_limit = calculate_fiber_limit
181
191
  job_fibers = []
182
192
  next_job_fibers = []
183
193
  source_fibers = []
@@ -187,7 +197,7 @@ module GraphQL
187
197
  while first_pass || job_fibers.any?
188
198
  first_pass = false
189
199
 
190
- while (f = (job_fibers.shift || spawn_job_fiber))
200
+ while (f = (job_fibers.shift || (((next_job_fibers.size + job_fibers.size) < jobs_fiber_limit) && spawn_job_fiber)))
191
201
  if f.alive?
192
202
  finished = run_fiber(f)
193
203
  if !finished
@@ -197,8 +207,8 @@ module GraphQL
197
207
  end
198
208
  join_queues(job_fibers, next_job_fibers)
199
209
 
200
- while source_fibers.any? || @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) }
201
- while (f = source_fibers.shift || spawn_source_fiber)
210
+ while (source_fibers.any? || @source_cache.each_value.any? { |group_sources| group_sources.each_value.any?(&:pending?) })
211
+ while (f = source_fibers.shift || (((job_fibers.size + source_fibers.size + next_source_fibers.size + next_job_fibers.size) < total_fiber_limit) && spawn_source_fiber))
202
212
  if f.alive?
203
213
  finished = run_fiber(f)
204
214
  if !finished
@@ -242,6 +252,17 @@ module GraphQL
242
252
 
243
253
  private
244
254
 
255
+ def calculate_fiber_limit
256
+ total_fiber_limit = @fiber_limit || Float::INFINITY
257
+ if total_fiber_limit < 4
258
+ raise ArgumentError, "Dataloader fiber limit is too low (#{total_fiber_limit}), it must be at least 4"
259
+ end
260
+ total_fiber_limit -= 1 # deduct one fiber for `manager`
261
+ # Deduct at least one fiber for sources
262
+ jobs_fiber_limit = total_fiber_limit - 2
263
+ return jobs_fiber_limit, total_fiber_limit
264
+ end
265
+
245
266
  def join_queues(prev_queue, new_queue)
246
267
  @nonblocking && Fiber.scheduler.run
247
268
  prev_queue.concat(new_queue)
@@ -12,12 +12,16 @@ module GraphQL
12
12
  end
13
13
 
14
14
  def self.resolve_each_depth(lazies_at_depth, dataloader)
15
- depths = lazies_at_depth.keys
16
- depths.sort!
17
- next_depth = depths.first
18
- if next_depth
19
- lazies = lazies_at_depth[next_depth]
20
- lazies_at_depth.delete(next_depth)
15
+ smallest_depth = nil
16
+ lazies_at_depth.each_key do |depth_key|
17
+ smallest_depth ||= depth_key
18
+ if depth_key < smallest_depth
19
+ smallest_depth = depth_key
20
+ end
21
+ end
22
+
23
+ if smallest_depth
24
+ lazies = lazies_at_depth.delete(smallest_depth)
21
25
  if lazies.any?
22
26
  dataloader.append_job {
23
27
  lazies.each(&:value) # resolve these Lazy instances
@@ -39,7 +39,7 @@ module GraphQL
39
39
  end
40
40
 
41
41
  def inspect
42
- if (name.nil? || parent_class.name.nil?) && parent_class.respond_to?(:mutation) && (mutation = parent_class.mutation)
42
+ if (name.nil? || parent_class&.name.nil?) && parent_class.respond_to?(:mutation) && (mutation = parent_class.mutation)
43
43
  "#{mutation.inspect}::#{parent_class.graphql_name}::InvalidNullError"
44
44
  else
45
45
  super
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+ module GraphQL
3
+ module Language
4
+ module Comment
5
+ def self.print(str, indent: '')
6
+ lines = str.split("\n").map do |line|
7
+ comment_str = "".dup
8
+ comment_str << indent
9
+ comment_str << "# "
10
+ comment_str << line
11
+ comment_str.rstrip
12
+ end
13
+
14
+ lines.join("\n") + "\n"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -18,6 +18,7 @@ module GraphQL
18
18
  include_built_in_directives: false, include_built_in_scalars: false, always_include_schema: false
19
19
  )
20
20
  @schema = schema
21
+ @context = context
21
22
  @always_include_schema = always_include_schema
22
23
  @include_introspection_types = include_introspection_types
23
24
  @include_built_in_scalars = include_built_in_scalars
@@ -58,6 +59,7 @@ module GraphQL
58
59
 
59
60
  GraphQL::Language::Nodes::ObjectTypeDefinition.new(
60
61
  name: object_type.graphql_name,
62
+ comment: object_type.comment,
61
63
  interfaces: ints,
62
64
  fields: build_field_nodes(@types.fields(object_type)),
63
65
  description: object_type.description,
@@ -68,6 +70,7 @@ module GraphQL
68
70
  def build_field_node(field)
69
71
  GraphQL::Language::Nodes::FieldDefinition.new(
70
72
  name: field.graphql_name,
73
+ comment: field.comment,
71
74
  arguments: build_argument_nodes(@types.arguments(field)),
72
75
  type: build_type_name_node(field.type),
73
76
  description: field.description,
@@ -78,6 +81,7 @@ module GraphQL
78
81
  def build_union_type_node(union_type)
79
82
  GraphQL::Language::Nodes::UnionTypeDefinition.new(
80
83
  name: union_type.graphql_name,
84
+ comment: union_type.comment,
81
85
  description: union_type.description,
82
86
  types: @types.possible_types(union_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
83
87
  directives: directives(union_type),
@@ -87,6 +91,7 @@ module GraphQL
87
91
  def build_interface_type_node(interface_type)
88
92
  GraphQL::Language::Nodes::InterfaceTypeDefinition.new(
89
93
  name: interface_type.graphql_name,
94
+ comment: interface_type.comment,
90
95
  interfaces: @types.interfaces(interface_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
91
96
  description: interface_type.description,
92
97
  fields: build_field_nodes(@types.fields(interface_type)),
@@ -97,6 +102,7 @@ module GraphQL
97
102
  def build_enum_type_node(enum_type)
98
103
  GraphQL::Language::Nodes::EnumTypeDefinition.new(
99
104
  name: enum_type.graphql_name,
105
+ comment: enum_type.comment,
100
106
  values: @types.enum_values(enum_type).sort_by(&:graphql_name).map do |enum_value|
101
107
  build_enum_value_node(enum_value)
102
108
  end,
@@ -108,6 +114,7 @@ module GraphQL
108
114
  def build_enum_value_node(enum_value)
109
115
  GraphQL::Language::Nodes::EnumValueDefinition.new(
110
116
  name: enum_value.graphql_name,
117
+ comment: enum_value.comment,
111
118
  description: enum_value.description,
112
119
  directives: directives(enum_value),
113
120
  )
@@ -116,6 +123,7 @@ module GraphQL
116
123
  def build_scalar_type_node(scalar_type)
117
124
  GraphQL::Language::Nodes::ScalarTypeDefinition.new(
118
125
  name: scalar_type.graphql_name,
126
+ comment: scalar_type.comment,
119
127
  description: scalar_type.description,
120
128
  directives: directives(scalar_type),
121
129
  )
@@ -130,6 +138,7 @@ module GraphQL
130
138
 
131
139
  argument_node = GraphQL::Language::Nodes::InputValueDefinition.new(
132
140
  name: argument.graphql_name,
141
+ comment: argument.comment,
133
142
  description: argument.description,
134
143
  type: build_type_name_node(argument.type),
135
144
  default_value: default_value,
@@ -142,6 +151,7 @@ module GraphQL
142
151
  def build_input_object_node(input_object)
143
152
  GraphQL::Language::Nodes::InputObjectTypeDefinition.new(
144
153
  name: input_object.graphql_name,
154
+ comment: input_object.comment,
145
155
  fields: build_argument_nodes(@types.arguments(input_object)),
146
156
  description: input_object.description,
147
157
  directives: directives(input_object),
@@ -259,7 +269,33 @@ module GraphQL
259
269
  end
260
270
  definitions = build_directive_nodes(dirs_to_build)
261
271
  all_types = @types.all_types
262
- type_nodes = build_type_definition_nodes(all_types + schema.extra_types)
272
+ type_nodes = build_type_definition_nodes(all_types)
273
+
274
+ if (ex_t = schema.extra_types).any?
275
+ dummy_query = Class.new(GraphQL::Schema::Object) do
276
+ graphql_name "DummyQuery"
277
+ (all_types + ex_t).each_with_index do |type, idx|
278
+ if !type.kind.input_object? && !type.introspection?
279
+ field "f#{idx}", type
280
+ end
281
+ end
282
+ end
283
+
284
+ extra_types_schema = Class.new(GraphQL::Schema) do
285
+ query(dummy_query)
286
+ end
287
+
288
+ extra_types_types = GraphQL::Query.new(extra_types_schema, "{ __typename }", context: @context).types # rubocop:disable Development/ContextIsPassedCop
289
+ # Temporarily replace `@types` with something from this example schema.
290
+ # It'd be much nicer to pass this in, but that would be a big refactor :S
291
+ prev_types = @types
292
+ @types = extra_types_types
293
+ type_nodes += build_type_definition_nodes(ex_t)
294
+ @types = prev_types
295
+ end
296
+
297
+ type_nodes.sort_by!(&:name)
298
+
263
299
  if @include_one_of
264
300
  # This may have been set to true when iterating over all types
265
301
  definitions.concat(build_directive_nodes([GraphQL::Schema::Directive::OneOf]))
@@ -282,9 +318,7 @@ module GraphQL
282
318
  types = types.reject { |type| type.kind.scalar? && type.default_scalar? }
283
319
  end
284
320
 
285
- types
286
- .map { |type| build_type_definition_node(type) }
287
- .sort_by(&:name)
321
+ types.map { |type| build_type_definition_node(type) }
288
322
  end
289
323
 
290
324
  def build_field_nodes(fields)
@@ -19,7 +19,7 @@ module GraphQL
19
19
  @scanner.eos?
20
20
  end
21
21
 
22
- attr_reader :pos
22
+ attr_reader :pos, :tokens_count
23
23
 
24
24
  def advance
25
25
  @scanner.skip(IGNORE_REGEXP)
@@ -57,20 +57,23 @@ module GraphQL
57
57
  @scanner.skip(IDENTIFIER_REGEXP)
58
58
  :IDENTIFIER
59
59
  when ByteFor::NUMBER
60
- @scanner.skip(NUMERIC_REGEXP)
60
+ if len = @scanner.skip(NUMERIC_REGEXP)
61
61
 
62
- if GraphQL.reject_numbers_followed_by_names
63
- new_pos = @scanner.pos
64
- peek_byte = @string.getbyte(new_pos)
65
- next_first_byte = FIRST_BYTES[peek_byte]
66
- if next_first_byte == ByteFor::NAME || next_first_byte == ByteFor::IDENTIFIER
67
- number_part = token_value
68
- name_part = @scanner.scan(IDENTIFIER_REGEXP)
69
- raise_parse_error("Name after number is not allowed (in `#{number_part}#{name_part}`)")
62
+ if GraphQL.reject_numbers_followed_by_names
63
+ new_pos = @scanner.pos
64
+ peek_byte = @string.getbyte(new_pos)
65
+ next_first_byte = FIRST_BYTES[peek_byte]
66
+ if next_first_byte == ByteFor::NAME || next_first_byte == ByteFor::IDENTIFIER
67
+ number_part = token_value
68
+ name_part = @scanner.scan(IDENTIFIER_REGEXP)
69
+ raise_parse_error("Name after number is not allowed (in `#{number_part}#{name_part}`)")
70
+ end
70
71
  end
72
+ # Check for a matched decimal:
73
+ @scanner[1] ? :FLOAT : :INT
74
+ else
75
+ raise_parse_error("Expected a number, but it was malformed (#{@string[@pos].inspect})")
71
76
  end
72
- # Check for a matched decimal:
73
- @scanner[1] ? :FLOAT : :INT
74
77
  when ByteFor::ELLIPSIS
75
78
  if @string.getbyte(@pos + 1) != 46 || @string.getbyte(@pos + 2) != 46
76
79
  raise_parse_error("Expected `...`, actual: #{@string[@pos..@pos + 2].inspect}")
@@ -270,15 +270,17 @@ module GraphQL
270
270
  "col: nil",
271
271
  "pos: nil",
272
272
  "filename: nil",
273
- "source: nil",
273
+ "source: nil"
274
274
  ]
275
275
 
276
+ IGNORED_MARSHALLING_KEYWORDS = [:comment]
277
+
276
278
  def generate_initialize
277
279
  return if method_defined?(:marshal_load, false) # checking for `:initialize` doesn't work right
278
280
 
279
281
  scalar_method_names = @scalar_methods
280
282
  # TODO: These probably should be scalar methods, but `types` returns an array
281
- [:types, :description].each do |extra_method|
283
+ [:types, :description, :comment].each do |extra_method|
282
284
  if method_defined?(extra_method)
283
285
  scalar_method_names += [extra_method]
284
286
  end
@@ -307,6 +309,12 @@ module GraphQL
307
309
  keywords = scalar_method_names.map { |m| "#{m}: #{m}"} +
308
310
  children_method_names.map { |m| "#{m}: #{m}" }
309
311
 
312
+ ignored_keywords = IGNORED_MARSHALLING_KEYWORDS.map do |keyword|
313
+ "#{keyword.to_s}: nil"
314
+ end
315
+
316
+ marshalling_method_names = all_method_names - IGNORED_MARSHALLING_KEYWORDS
317
+
310
318
  module_eval <<-RUBY, __FILE__, __LINE__
311
319
  def initialize(#{arguments.join(", ")})
312
320
  @line = line
@@ -317,7 +325,7 @@ module GraphQL
317
325
  #{assignments.join("\n")}
318
326
  end
319
327
 
320
- def self.from_a(filename, line, col, #{all_method_names.join(", ")})
328
+ def self.from_a(filename, line, col, #{marshalling_method_names.join(", ")}, #{ignored_keywords.join(", ")})
321
329
  self.new(filename: filename, line: line, col: col, #{keywords.join(", ")})
322
330
  end
323
331
 
@@ -325,12 +333,12 @@ module GraphQL
325
333
  [
326
334
  line, col, # use methods here to force them to be calculated
327
335
  @filename,
328
- #{all_method_names.map { |n| "@#{n}," }.join}
336
+ #{marshalling_method_names.map { |n| "@#{n}," }.join}
329
337
  ]
330
338
  end
331
339
 
332
340
  def marshal_load(values)
333
- @line, @col, @filename #{all_method_names.map { |n| ", @#{n}"}.join} = values
341
+ @line, @col, @filename #{marshalling_method_names.map { |n| ", @#{n}"}.join} = values
334
342
  end
335
343
  RUBY
336
344
  end
@@ -635,7 +643,7 @@ module GraphQL
635
643
  end
636
644
 
637
645
  class ScalarTypeDefinition < AbstractNode
638
- attr_reader :description
646
+ attr_reader :description, :comment
639
647
  scalar_methods :name
640
648
  children_methods({
641
649
  directives: GraphQL::Language::Nodes::Directive,
@@ -652,7 +660,7 @@ module GraphQL
652
660
  end
653
661
 
654
662
  class InputValueDefinition < AbstractNode
655
- attr_reader :description
663
+ attr_reader :description, :comment
656
664
  scalar_methods :name, :type, :default_value
657
665
  children_methods({
658
666
  directives: GraphQL::Language::Nodes::Directive,
@@ -661,7 +669,7 @@ module GraphQL
661
669
  end
662
670
 
663
671
  class FieldDefinition < AbstractNode
664
- attr_reader :description
672
+ attr_reader :description, :comment
665
673
  scalar_methods :name, :type
666
674
  children_methods({
667
675
  arguments: GraphQL::Language::Nodes::InputValueDefinition,
@@ -681,7 +689,7 @@ module GraphQL
681
689
  end
682
690
 
683
691
  class ObjectTypeDefinition < AbstractNode
684
- attr_reader :description
692
+ attr_reader :description, :comment
685
693
  scalar_methods :name, :interfaces
686
694
  children_methods({
687
695
  directives: GraphQL::Language::Nodes::Directive,
@@ -700,7 +708,7 @@ module GraphQL
700
708
  end
701
709
 
702
710
  class InterfaceTypeDefinition < AbstractNode
703
- attr_reader :description
711
+ attr_reader :description, :comment
704
712
  scalar_methods :name
705
713
  children_methods({
706
714
  interfaces: GraphQL::Language::Nodes::TypeName,
@@ -721,7 +729,7 @@ module GraphQL
721
729
  end
722
730
 
723
731
  class UnionTypeDefinition < AbstractNode
724
- attr_reader :description, :types
732
+ attr_reader :description, :comment, :types
725
733
  scalar_methods :name
726
734
  children_methods({
727
735
  directives: GraphQL::Language::Nodes::Directive,
@@ -739,7 +747,7 @@ module GraphQL
739
747
  end
740
748
 
741
749
  class EnumValueDefinition < AbstractNode
742
- attr_reader :description
750
+ attr_reader :description, :comment
743
751
  scalar_methods :name
744
752
  children_methods({
745
753
  directives: GraphQL::Language::Nodes::Directive,
@@ -748,7 +756,7 @@ module GraphQL
748
756
  end
749
757
 
750
758
  class EnumTypeDefinition < AbstractNode
751
- attr_reader :description
759
+ attr_reader :description, :comment
752
760
  scalar_methods :name
753
761
  children_methods({
754
762
  directives: GraphQL::Language::Nodes::Directive,
@@ -767,7 +775,7 @@ module GraphQL
767
775
  end
768
776
 
769
777
  class InputObjectTypeDefinition < AbstractNode
770
- attr_reader :description
778
+ attr_reader :description, :comment
771
779
  scalar_methods :name
772
780
  children_methods({
773
781
  directives: GraphQL::Language::Nodes::Directive,
@@ -49,6 +49,11 @@ module GraphQL
49
49
  end
50
50
  end
51
51
 
52
+ def tokens_count
53
+ parse
54
+ @lexer.tokens_count
55
+ end
56
+
52
57
  def line_at(pos)
53
58
  line = lines_at.bsearch_index { |l| l >= pos }
54
59
  if line.nil?
@@ -255,14 +255,14 @@ module GraphQL
255
255
 
256
256
 
257
257
  def print_scalar_type_definition(scalar_type, extension: false)
258
- extension ? print_string("extend ") : print_description(scalar_type)
258
+ extension ? print_string("extend ") : print_description_and_comment(scalar_type)
259
259
  print_string("scalar ")
260
260
  print_string(scalar_type.name)
261
261
  print_directives(scalar_type.directives)
262
262
  end
263
263
 
264
264
  def print_object_type_definition(object_type, extension: false)
265
- extension ? print_string("extend ") : print_description(object_type)
265
+ extension ? print_string("extend ") : print_description_and_comment(object_type)
266
266
  print_string("type ")
267
267
  print_string(object_type.name)
268
268
  print_implements(object_type) unless object_type.interfaces.empty?
@@ -294,7 +294,7 @@ module GraphQL
294
294
  end
295
295
 
296
296
  def print_arguments(arguments, indent: "")
297
- if arguments.all? { |arg| !arg.description }
297
+ if arguments.all? { |arg| !arg.description && !arg.comment }
298
298
  print_string("(")
299
299
  arguments.each_with_index do |arg, i|
300
300
  print_input_value_definition(arg)
@@ -306,6 +306,7 @@ module GraphQL
306
306
 
307
307
  print_string("(\n")
308
308
  arguments.each_with_index do |arg, i|
309
+ print_comment(arg, indent: " " + indent, first_in_block: i == 0)
309
310
  print_description(arg, indent: " " + indent, first_in_block: i == 0)
310
311
  print_string(" ")
311
312
  print_string(indent)
@@ -328,7 +329,7 @@ module GraphQL
328
329
  end
329
330
 
330
331
  def print_interface_type_definition(interface_type, extension: false)
331
- extension ? print_string("extend ") : print_description(interface_type)
332
+ extension ? print_string("extend ") : print_description_and_comment(interface_type)
332
333
  print_string("interface ")
333
334
  print_string(interface_type.name)
334
335
  print_implements(interface_type) if interface_type.interfaces.any?
@@ -337,7 +338,7 @@ module GraphQL
337
338
  end
338
339
 
339
340
  def print_union_type_definition(union_type, extension: false)
340
- extension ? print_string("extend ") : print_description(union_type)
341
+ extension ? print_string("extend ") : print_description_and_comment(union_type)
341
342
  print_string("union ")
342
343
  print_string(union_type.name)
343
344
  print_directives(union_type.directives)
@@ -355,7 +356,7 @@ module GraphQL
355
356
  end
356
357
 
357
358
  def print_enum_type_definition(enum_type, extension: false)
358
- extension ? print_string("extend ") : print_description(enum_type)
359
+ extension ? print_string("extend ") : print_description_and_comment(enum_type)
359
360
  print_string("enum ")
360
361
  print_string(enum_type.name)
361
362
  print_directives(enum_type.directives)
@@ -363,6 +364,7 @@ module GraphQL
363
364
  print_string(" {\n")
364
365
  enum_type.values.each.with_index do |value, i|
365
366
  print_description(value, indent: " ", first_in_block: i == 0)
367
+ print_comment(value, indent: " ", first_in_block: i == 0)
366
368
  print_enum_value_definition(value)
367
369
  end
368
370
  print_string("}")
@@ -377,7 +379,7 @@ module GraphQL
377
379
  end
378
380
 
379
381
  def print_input_object_type_definition(input_object_type, extension: false)
380
- extension ? print_string("extend ") : print_description(input_object_type)
382
+ extension ? print_string("extend ") : print_description_and_comment(input_object_type)
381
383
  print_string("input ")
382
384
  print_string(input_object_type.name)
383
385
  print_directives(input_object_type.directives)
@@ -385,6 +387,7 @@ module GraphQL
385
387
  print_string(" {\n")
386
388
  input_object_type.fields.each.with_index do |field, i|
387
389
  print_description(field, indent: " ", first_in_block: i == 0)
390
+ print_comment(field, indent: " ", first_in_block: i == 0)
388
391
  print_string(" ")
389
392
  print_input_value_definition(field)
390
393
  print_string("\n")
@@ -424,6 +427,18 @@ module GraphQL
424
427
  print_string(GraphQL::Language::BlockString.print(node.description, indent: indent))
425
428
  end
426
429
 
430
+ def print_comment(node, indent: "", first_in_block: true)
431
+ return unless node.comment
432
+
433
+ print_string("\n") if indent != "" && !first_in_block
434
+ print_string(GraphQL::Language::Comment.print(node.comment, indent: indent))
435
+ end
436
+
437
+ def print_description_and_comment(node)
438
+ print_description(node)
439
+ print_comment(node)
440
+ end
441
+
427
442
  def print_field_definitions(fields)
428
443
  return if fields.empty?
429
444
 
@@ -431,6 +446,7 @@ module GraphQL
431
446
  i = 0
432
447
  fields.each do |field|
433
448
  print_description(field, indent: " ", first_in_block: i == 0)
449
+ print_comment(field, indent: " ", first_in_block: i == 0)
434
450
  print_string(" ")
435
451
  print_field_definition(field)
436
452
  print_string("\n")