diff --git a/src/language/__tests__/kitchen-sink.graphql b/src/language/__tests__/kitchen-sink.graphql index 993de9ad02..1a64133297 100644 --- a/src/language/__tests__/kitchen-sink.graphql +++ b/src/language/__tests__/kitchen-sink.graphql @@ -52,6 +52,7 @@ fragment frag on Friend { } { + # Here is a comment unnamed(truthy: true, falsey: false, nullish: null), query } diff --git a/src/language/__tests__/printer-test.js b/src/language/__tests__/printer-test.js index 227585ce7f..e19630b9ae 100644 --- a/src/language/__tests__/printer-test.js +++ b/src/language/__tests__/printer-test.js @@ -36,6 +36,18 @@ describe('Printer', () => { }); it('correctly prints non-query operations without name', () => { + const queryWithComment = parse(dedent`query { + # Test + id + }`); + console.log(JSON.stringify(queryWithComment, null, 2)); + expect(print(queryWithComment)).to.equal(dedent` + { + # Test + id + } + `); + const queryAstShorthanded = parse('query { id, name }'); expect(print(queryAstShorthanded)).to.equal(dedent` { diff --git a/src/language/ast.js b/src/language/ast.js index 7141dcf9ad..0aeae173f4 100644 --- a/src/language/ast.js +++ b/src/language/ast.js @@ -126,6 +126,7 @@ export type ASTNode = | SelectionSetNode | FieldNode | ArgumentNode + | CommentNode | FragmentSpreadNode | InlineFragmentNode | FragmentDefinitionNode @@ -232,6 +233,11 @@ export type ArgumentNode = { value: ValueNode; }; +export type CommentNode = { + kind: 'Comment'; + loc?: Location; + value: string; +}; // Fragments diff --git a/src/language/kinds.js b/src/language/kinds.js index 774fc1606d..a126d9b7b0 100644 --- a/src/language/kinds.js +++ b/src/language/kinds.js @@ -21,6 +21,7 @@ export const VARIABLE = 'Variable'; export const SELECTION_SET = 'SelectionSet'; export const FIELD = 'Field'; export const ARGUMENT = 'Argument'; +export const COMMENT = 'Comment'; // Fragments diff --git a/src/language/lexer.js b/src/language/lexer.js index 4f8118588c..b14d2ebe25 100644 --- a/src/language/lexer.js +++ b/src/language/lexer.js @@ -40,9 +40,7 @@ export function createLexer( function advanceLexer() { let token = this.lastToken = this.token; if (token.kind !== EOF) { - do { - token = token.next = readToken(this, token); - } while (token.kind === COMMENT); + token = token.next = readToken(this, token); this.token = token; } return token; diff --git a/src/language/parser.js b/src/language/parser.js index 7c65aca7bf..a19ff812dc 100644 --- a/src/language/parser.js +++ b/src/language/parser.js @@ -33,6 +33,7 @@ import type { SelectionNode, FieldNode, ArgumentNode, + CommentNode, FragmentSpreadNode, InlineFragmentNode, @@ -80,6 +81,7 @@ import { SELECTION_SET, FIELD, ARGUMENT, + COMMENT, FRAGMENT_SPREAD, INLINE_FRAGMENT, @@ -435,6 +437,19 @@ function parseArgument(lexer: Lexer<*>): ArgumentNode { }; } +/** + * Coment : Value + */ +// FIXME This is never used anywhere +function parseComment(lexer: Lexer<*>): CommentNode { + const start = lexer.token; + return { + kind: COMMENT, + value: expect(lexer, TokenKind.COMMENT), + loc: loc(lexer, start) + }; +} + // Implements the parsing rules in the Fragments section. diff --git a/src/language/printer.js b/src/language/printer.js index e056ce0e9f..8de37a3f07 100644 --- a/src/language/printer.js +++ b/src/language/printer.js @@ -52,6 +52,8 @@ const printDocASTReducer = { Argument: ({ name, value }) => name + ': ' + value, + Comment: ({ value }) => '# ' + value, + // Fragments FragmentSpread: ({ name, directives }) => diff --git a/src/language/visitor.js b/src/language/visitor.js index d57debaf00..bfe05a438c 100644 --- a/src/language/visitor.js +++ b/src/language/visitor.js @@ -18,6 +18,7 @@ export const QueryDocumentKeys = { SelectionSet: [ 'selections' ], Field: [ 'alias', 'name', 'arguments', 'directives', 'selectionSet' ], Argument: [ 'name', 'value' ], + Comment: [], FragmentSpread: [ 'name', 'directives' ], InlineFragment: [ 'typeCondition', 'directives', 'selectionSet' ],