Skip to content

Commit 23c2770

Browse files
authored
Merge pull request #5067 from productboard/feat/vbo-comments-vol-2
Support for comments v2
2 parents 155b2f4 + 0211989 commit 23c2770

File tree

23 files changed

+431
-33
lines changed

23 files changed

+431
-33
lines changed

guides/fields/introduction.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ The different elements of field definition are addressed below:
2121

2222
- [Names](#field-names) identify the field in GraphQL
2323
- [Return types](#field-return-type) say what kind of data this field returns
24-
- [Documentation](#field-documentation) includes description and deprecation notes
24+
- [Documentation](#field-documentation) includes description, comments and deprecation notes
2525
- [Resolution behavior](#field-resolution) hooks up Ruby code to the GraphQL field
2626
- [Arguments](#field-arguments) allow fields to take input when they're queried
2727
- [Extra field metadata](#extra-field-metadata) for low-level access to the GraphQL-Ruby runtime
@@ -67,7 +67,7 @@ field :scores, [Integer, null: true] # `[Int]`, may return a list or `nil`, the
6767

6868
## Field Documentation
6969

70-
Fields may be documented with a __description__ and may be __deprecated__.
70+
Fields may be documented with a __description__, __comment__ and may be __deprecated__.
7171

7272
__Descriptions__ can be added with the `field(...)` method as a positional argument, a keyword argument, or inside the block:
7373

@@ -85,6 +85,26 @@ field :name, String, null: false do
8585
end
8686
```
8787

88+
__Comments__ can be added with the `field(...)` method as a keyword argument, or inside the block:
89+
```ruby
90+
# `comment:` keyword
91+
field :name, String, null: false, comment: "Rename to full name"
92+
93+
# inside the block
94+
field :name, String, null: false do
95+
comment "Rename to full name"
96+
end
97+
```
98+
99+
Generates field name with comment above "Rename to full name" above.
100+
101+
```graphql
102+
type Foo {
103+
# Rename to full name
104+
name: String!
105+
}
106+
```
107+
88108
__Deprecated__ fields can be marked by adding a `deprecation_reason:` keyword argument:
89109

90110
```ruby

guides/type_definitions/enums.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ end
5959
Each value may have:
6060

6161
- A description (as the second argument or `description:` keyword)
62+
- A comment (as a `comment:` keyword)
6263
- A deprecation reason (as `deprecation_reason:`), marking this value as deprecated
6364
- A corresponding Ruby value (as `value:`), see below
6465

guides/type_definitions/interfaces.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Then, include that into each interface:
8080
```ruby
8181
module Types::RetailItem
8282
include Types::BaseInterface
83+
comment "TODO comment in the RetailItem interface"
8384
description "Something that can be bought"
8485
field :price, Types::Price, "How much this item costs", null: false
8586

guides/type_definitions/objects.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ end
7171

7272
# then...
7373
class Types::TodoList < Types::BaseObject
74+
comment "Comment of the TodoList type"
7475
description "A list of items which may be completed"
7576

7677
field :name, String, "The unique name of this list", null: false

guides/type_definitions/scalars.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ end
7373

7474
# app/graphql/types/url.rb
7575
class Types::Url < Types::BaseScalar
76+
comment "TODO comment of the scalar"
7677
description "A valid URL, transported as a string"
7778

7879
def self.coerce_input(input_value, context)

guides/type_definitions/unions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ Then, extend that one for each union in your schema:
5454

5555
```ruby
5656
class Types::CommentSubject < Types::BaseUnion
57+
comment "TODO comment on the union"
5758
description "Objects which may be commented on"
5859
possible_types Types::Post, Types::Image
5960

lib/graphql/language.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22
require "graphql/language/block_string"
3+
require "graphql/language/comment"
34
require "graphql/language/printer"
45
require "graphql/language/sanitized_printer"
56
require "graphql/language/document_from_schema_definition"

lib/graphql/language/comment.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

lib/graphql/language/document_from_schema_definition.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ def build_object_type_node(object_type)
5858

5959
GraphQL::Language::Nodes::ObjectTypeDefinition.new(
6060
name: object_type.graphql_name,
61+
comment: object_type.comment,
6162
interfaces: ints,
6263
fields: build_field_nodes(@types.fields(object_type)),
6364
description: object_type.description,
@@ -68,6 +69,7 @@ def build_object_type_node(object_type)
6869
def build_field_node(field)
6970
GraphQL::Language::Nodes::FieldDefinition.new(
7071
name: field.graphql_name,
72+
comment: field.comment,
7173
arguments: build_argument_nodes(@types.arguments(field)),
7274
type: build_type_name_node(field.type),
7375
description: field.description,
@@ -78,6 +80,7 @@ def build_field_node(field)
7880
def build_union_type_node(union_type)
7981
GraphQL::Language::Nodes::UnionTypeDefinition.new(
8082
name: union_type.graphql_name,
83+
comment: union_type.comment,
8184
description: union_type.description,
8285
types: @types.possible_types(union_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
8386
directives: directives(union_type),
@@ -87,6 +90,7 @@ def build_union_type_node(union_type)
8790
def build_interface_type_node(interface_type)
8891
GraphQL::Language::Nodes::InterfaceTypeDefinition.new(
8992
name: interface_type.graphql_name,
93+
comment: interface_type.comment,
9094
interfaces: @types.interfaces(interface_type).sort_by(&:graphql_name).map { |type| build_type_name_node(type) },
9195
description: interface_type.description,
9296
fields: build_field_nodes(@types.fields(interface_type)),
@@ -97,6 +101,7 @@ def build_interface_type_node(interface_type)
97101
def build_enum_type_node(enum_type)
98102
GraphQL::Language::Nodes::EnumTypeDefinition.new(
99103
name: enum_type.graphql_name,
104+
comment: enum_type.comment,
100105
values: @types.enum_values(enum_type).sort_by(&:graphql_name).map do |enum_value|
101106
build_enum_value_node(enum_value)
102107
end,
@@ -108,6 +113,7 @@ def build_enum_type_node(enum_type)
108113
def build_enum_value_node(enum_value)
109114
GraphQL::Language::Nodes::EnumValueDefinition.new(
110115
name: enum_value.graphql_name,
116+
comment: enum_value.comment,
111117
description: enum_value.description,
112118
directives: directives(enum_value),
113119
)
@@ -116,6 +122,7 @@ def build_enum_value_node(enum_value)
116122
def build_scalar_type_node(scalar_type)
117123
GraphQL::Language::Nodes::ScalarTypeDefinition.new(
118124
name: scalar_type.graphql_name,
125+
comment: scalar_type.comment,
119126
description: scalar_type.description,
120127
directives: directives(scalar_type),
121128
)
@@ -130,6 +137,7 @@ def build_argument_node(argument)
130137

131138
argument_node = GraphQL::Language::Nodes::InputValueDefinition.new(
132139
name: argument.graphql_name,
140+
comment: argument.comment,
133141
description: argument.description,
134142
type: build_type_name_node(argument.type),
135143
default_value: default_value,
@@ -142,6 +150,7 @@ def build_argument_node(argument)
142150
def build_input_object_node(input_object)
143151
GraphQL::Language::Nodes::InputObjectTypeDefinition.new(
144152
name: input_object.graphql_name,
153+
comment: input_object.comment,
145154
fields: build_argument_nodes(@types.arguments(input_object)),
146155
description: input_object.description,
147156
directives: directives(input_object),

lib/graphql/language/nodes.rb

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -270,15 +270,17 @@ def scalars
270270
"col: nil",
271271
"pos: nil",
272272
"filename: nil",
273-
"source: nil",
273+
"source: nil"
274274
]
275275

276+
IGNORED_MARSHALLING_KEYWORDS = [:comment]
277+
276278
def generate_initialize
277279
return if method_defined?(:marshal_load, false) # checking for `:initialize` doesn't work right
278280

279281
scalar_method_names = @scalar_methods
280282
# 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|
282284
if method_defined?(extra_method)
283285
scalar_method_names += [extra_method]
284286
end
@@ -307,6 +309,12 @@ def generate_initialize
307309
keywords = scalar_method_names.map { |m| "#{m}: #{m}"} +
308310
children_method_names.map { |m| "#{m}: #{m}" }
309311

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+
310318
module_eval <<-RUBY, __FILE__, __LINE__
311319
def initialize(#{arguments.join(", ")})
312320
@line = line
@@ -317,20 +325,20 @@ def initialize(#{arguments.join(", ")})
317325
#{assignments.join("\n")}
318326
end
319327
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(", ")})
321329
self.new(filename: filename, line: line, col: col, #{keywords.join(", ")})
322330
end
323331
324332
def marshal_dump
325333
[
326334
line, col, # use methods here to force them to be calculated
327335
@filename,
328-
#{all_method_names.map { |n| "@#{n}," }.join}
336+
#{marshalling_method_names.map { |n| "@#{n}," }.join}
329337
]
330338
end
331339
332340
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
334342
end
335343
RUBY
336344
end
@@ -635,7 +643,7 @@ class SchemaExtension < AbstractNode
635643
end
636644

637645
class ScalarTypeDefinition < AbstractNode
638-
attr_reader :description
646+
attr_reader :description, :comment
639647
scalar_methods :name
640648
children_methods({
641649
directives: GraphQL::Language::Nodes::Directive,
@@ -652,7 +660,7 @@ class ScalarTypeExtension < AbstractNode
652660
end
653661

654662
class InputValueDefinition < AbstractNode
655-
attr_reader :description
663+
attr_reader :description, :comment
656664
scalar_methods :name, :type, :default_value
657665
children_methods({
658666
directives: GraphQL::Language::Nodes::Directive,
@@ -661,7 +669,7 @@ class InputValueDefinition < AbstractNode
661669
end
662670

663671
class FieldDefinition < AbstractNode
664-
attr_reader :description
672+
attr_reader :description, :comment
665673
scalar_methods :name, :type
666674
children_methods({
667675
arguments: GraphQL::Language::Nodes::InputValueDefinition,
@@ -681,7 +689,7 @@ def merge(new_options)
681689
end
682690

683691
class ObjectTypeDefinition < AbstractNode
684-
attr_reader :description
692+
attr_reader :description, :comment
685693
scalar_methods :name, :interfaces
686694
children_methods({
687695
directives: GraphQL::Language::Nodes::Directive,
@@ -700,7 +708,7 @@ class ObjectTypeExtension < AbstractNode
700708
end
701709

702710
class InterfaceTypeDefinition < AbstractNode
703-
attr_reader :description
711+
attr_reader :description, :comment
704712
scalar_methods :name
705713
children_methods({
706714
interfaces: GraphQL::Language::Nodes::TypeName,
@@ -721,7 +729,7 @@ class InterfaceTypeExtension < AbstractNode
721729
end
722730

723731
class UnionTypeDefinition < AbstractNode
724-
attr_reader :description, :types
732+
attr_reader :description, :comment, :types
725733
scalar_methods :name
726734
children_methods({
727735
directives: GraphQL::Language::Nodes::Directive,
@@ -739,7 +747,7 @@ class UnionTypeExtension < AbstractNode
739747
end
740748

741749
class EnumValueDefinition < AbstractNode
742-
attr_reader :description
750+
attr_reader :description, :comment
743751
scalar_methods :name
744752
children_methods({
745753
directives: GraphQL::Language::Nodes::Directive,
@@ -748,7 +756,7 @@ class EnumValueDefinition < AbstractNode
748756
end
749757

750758
class EnumTypeDefinition < AbstractNode
751-
attr_reader :description
759+
attr_reader :description, :comment
752760
scalar_methods :name
753761
children_methods({
754762
directives: GraphQL::Language::Nodes::Directive,
@@ -767,7 +775,7 @@ class EnumTypeExtension < AbstractNode
767775
end
768776

769777
class InputObjectTypeDefinition < AbstractNode
770-
attr_reader :description
778+
attr_reader :description, :comment
771779
scalar_methods :name
772780
children_methods({
773781
directives: GraphQL::Language::Nodes::Directive,

0 commit comments

Comments
 (0)