diff --git a/src/language/parser.js b/src/language/parser.js index 37ba2e1fb3..8e105f8405 100644 --- a/src/language/parser.js +++ b/src/language/parser.js @@ -488,7 +488,9 @@ function parseFragment( ): FragmentSpreadNode | InlineFragmentNode { const start = lexer.token; expect(lexer, TokenKind.SPREAD); - if (peek(lexer, TokenKind.NAME) && lexer.token.value !== 'on') { + + const hasTypeCondition = skipKeyword(lexer, 'on'); + if (!hasTypeCondition && peek(lexer, TokenKind.NAME)) { return { kind: Kind.FRAGMENT_SPREAD, name: parseFragmentName(lexer), @@ -496,14 +498,9 @@ function parseFragment( loc: loc(lexer, start), }; } - let typeCondition; - if (lexer.token.value === 'on') { - lexer.advance(); - typeCondition = parseNamedType(lexer); - } return { kind: Kind.INLINE_FRAGMENT, - typeCondition, + typeCondition: hasTypeCondition ? parseNamedType(lexer) : undefined, directives: parseDirectives(lexer, false), selectionSet: parseSelectionSet(lexer), loc: loc(lexer, start), @@ -912,8 +909,7 @@ function parseObjectTypeDefinition(lexer: Lexer<*>): ObjectTypeDefinitionNode { */ function parseImplementsInterfaces(lexer: Lexer<*>): Array { const types = []; - if (lexer.token.value === 'implements') { - lexer.advance(); + if (skipKeyword(lexer, 'implements')) { // Optional leading ampersand skip(lexer, TokenKind.AMP); do { @@ -1487,11 +1483,11 @@ function peek(lexer: Lexer<*>, kind: TokenKindEnum): boolean { * the lexer. Otherwise, do not change the parser state and return false. */ function skip(lexer: Lexer<*>, kind: TokenKindEnum): boolean { - const match = lexer.token.kind === kind; - if (match) { + if (lexer.token.kind === kind) { lexer.advance(); + return true; } - return match; + return false; } /** @@ -1512,21 +1508,31 @@ function expect(lexer: Lexer<*>, kind: TokenKindEnum): Token { } /** - * If the next token is a keyword with the given value, return that token after - * advancing the lexer. Otherwise, do not change the parser state and return - * false. + * If the next token is a keyword with the given value, return true after advancing + * the lexer. Otherwise, do not change the parser state and return false. */ -function expectKeyword(lexer: Lexer<*>, value: string): Token { +function skipKeyword(lexer: Lexer<*>, value: string): boolean { const token = lexer.token; if (token.kind === TokenKind.NAME && token.value === value) { lexer.advance(); - return token; + return true; + } + return false; +} + +/** + * If the next token is a keyword with the given value, return that token after + * advancing the lexer. Otherwise, do not change the parser state and throw + * an error. + */ +function expectKeyword(lexer: Lexer<*>, value: string): void { + if (!skipKeyword(lexer, value)) { + throw syntaxError( + lexer.source, + lexer.token.start, + `Expected "${value}", found ${getTokenDesc(lexer.token)}`, + ); } - throw syntaxError( - lexer.source, - token.start, - `Expected "${value}", found ${getTokenDesc(token)}`, - ); } /**