Skip to content

parser: Convert error messages to match common standard of this lib #2175

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/execution/__tests__/sync-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ describe('Execute: synchronously when possible', () => {
expect(result).to.deep.equal({
errors: [
{
message: 'Syntax Error: Expected Name, found {',
message: 'Syntax Error: Expected Name, found "{".',
locations: [{ line: 1, column: 29 }],
},
],
Expand Down
48 changes: 26 additions & 22 deletions src/language/__tests__/lexer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { GraphQLError } from '../../error/GraphQLError';

import { Source } from '../source';
import { TokenKind } from '../tokenKind';
import { createLexer, isPunctuatorToken } from '../lexer';
import { createLexer, isPunctuatorTokenKind } from '../lexer';

function lexOne(str) {
const lexer = createLexer(new Source(str));
Expand Down Expand Up @@ -905,30 +905,34 @@ describe('Lexer', () => {
});
});

describe('isPunctuatorToken', () => {
describe('isPunctuatorTokenKind', () => {
function isPunctuatorToken(text) {
return isPunctuatorTokenKind(lexOne(text).kind);
}

it('returns true for punctuator tokens', () => {
expect(isPunctuatorToken(lexOne('!'))).to.equal(true);
expect(isPunctuatorToken(lexOne('$'))).to.equal(true);
expect(isPunctuatorToken(lexOne('&'))).to.equal(true);
expect(isPunctuatorToken(lexOne('('))).to.equal(true);
expect(isPunctuatorToken(lexOne(')'))).to.equal(true);
expect(isPunctuatorToken(lexOne('...'))).to.equal(true);
expect(isPunctuatorToken(lexOne(':'))).to.equal(true);
expect(isPunctuatorToken(lexOne('='))).to.equal(true);
expect(isPunctuatorToken(lexOne('@'))).to.equal(true);
expect(isPunctuatorToken(lexOne('['))).to.equal(true);
expect(isPunctuatorToken(lexOne(']'))).to.equal(true);
expect(isPunctuatorToken(lexOne('{'))).to.equal(true);
expect(isPunctuatorToken(lexOne('|'))).to.equal(true);
expect(isPunctuatorToken(lexOne('}'))).to.equal(true);
expect(isPunctuatorToken('!')).to.equal(true);
expect(isPunctuatorToken('$')).to.equal(true);
expect(isPunctuatorToken('&')).to.equal(true);
expect(isPunctuatorToken('(')).to.equal(true);
expect(isPunctuatorToken(')')).to.equal(true);
expect(isPunctuatorToken('...')).to.equal(true);
expect(isPunctuatorToken(':')).to.equal(true);
expect(isPunctuatorToken('=')).to.equal(true);
expect(isPunctuatorToken('@')).to.equal(true);
expect(isPunctuatorToken('[')).to.equal(true);
expect(isPunctuatorToken(']')).to.equal(true);
expect(isPunctuatorToken('{')).to.equal(true);
expect(isPunctuatorToken('|')).to.equal(true);
expect(isPunctuatorToken('}')).to.equal(true);
});

it('returns false for non-punctuator tokens', () => {
expect(isPunctuatorToken(lexOne(''))).to.equal(false);
expect(isPunctuatorToken(lexOne('name'))).to.equal(false);
expect(isPunctuatorToken(lexOne('1'))).to.equal(false);
expect(isPunctuatorToken(lexOne('3.14'))).to.equal(false);
expect(isPunctuatorToken(lexOne('"str"'))).to.equal(false);
expect(isPunctuatorToken(lexOne('"""str"""'))).to.equal(false);
expect(isPunctuatorToken('')).to.equal(false);
expect(isPunctuatorToken('name')).to.equal(false);
expect(isPunctuatorToken('1')).to.equal(false);
expect(isPunctuatorToken('3.14')).to.equal(false);
expect(isPunctuatorToken('"str"')).to.equal(false);
expect(isPunctuatorToken('"""str"""')).to.equal(false);
});
});
20 changes: 10 additions & 10 deletions src/language/__tests__/parser-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ describe('Parser', () => {
}

expect(caughtError).to.deep.contain({
message: 'Syntax Error: Expected Name, found <EOF>',
message: 'Syntax Error: Expected Name, found <EOF>.',
positions: [1],
locations: [{ line: 1, column: 2 }],
});

expect(String(caughtError) + '\n').to.equal(dedent`
Syntax Error: Expected Name, found <EOF>
Syntax Error: Expected Name, found <EOF>.

GraphQL request:1:2
1 | {
Expand All @@ -57,22 +57,22 @@ describe('Parser', () => {
{ ...MissingOn }
fragment MissingOn Type
`).to.deep.include({
message: 'Syntax Error: Expected "on", found Name "Type"',
message: 'Syntax Error: Expected "on", found Name "Type".',
locations: [{ line: 3, column: 26 }],
});

expectSyntaxError('{ field: {} }').to.deep.include({
message: 'Syntax Error: Expected Name, found {',
message: 'Syntax Error: Expected Name, found "{".',
locations: [{ line: 1, column: 10 }],
});

expectSyntaxError('notanoperation Foo { field }').to.deep.include({
message: 'Syntax Error: Unexpected Name "notanoperation"',
message: 'Syntax Error: Unexpected Name "notanoperation".',
locations: [{ line: 1, column: 1 }],
});

expectSyntaxError('...').to.deep.include({
message: 'Syntax Error: Unexpected ...',
message: 'Syntax Error: Unexpected "...".',
locations: [{ line: 1, column: 1 }],
});
});
Expand All @@ -85,7 +85,7 @@ describe('Parser', () => {
caughtError = error;
}
expect(String(caughtError) + '\n').to.equal(dedent`
Syntax Error: Expected {, found <EOF>
Syntax Error: Expected "{", found <EOF>.

MyQuery.graphql:1:6
1 | query
Expand All @@ -103,7 +103,7 @@ describe('Parser', () => {
expectSyntaxError(
'query Foo($x: Complex = { a: { b: [ $var ] } }) { field }',
).to.deep.equal({
message: 'Syntax Error: Unexpected $',
message: 'Syntax Error: Unexpected "$".',
locations: [{ line: 1, column: 37 }],
});
});
Expand All @@ -116,14 +116,14 @@ describe('Parser', () => {

it('does not accept fragments named "on"', () => {
expectSyntaxError('fragment on on on { on }').to.deep.equal({
message: 'Syntax Error: Unexpected Name "on"',
message: 'Syntax Error: Unexpected Name "on".',
locations: [{ line: 1, column: 10 }],
});
});

it('does not accept fragments spread of "on"', () => {
expectSyntaxError('{ ...on }').to.deep.equal({
message: 'Syntax Error: Expected Name, found }',
message: 'Syntax Error: Expected Name, found "}".',
locations: [{ line: 1, column: 9 }],
});
});
Expand Down
24 changes: 12 additions & 12 deletions src/language/__tests__/schema-parser-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ describe('Schema Parser', () => {

it('Extension without anything throws', () => {
expectSyntaxError('extend type Hello').to.deep.equal({
message: 'Syntax Error: Unexpected <EOF>',
message: 'Syntax Error: Unexpected <EOF>.',
locations: [{ line: 1, column: 18 }],
});
});
Expand All @@ -233,7 +233,7 @@ describe('Schema Parser', () => {
world: String
}
`).to.deep.equal({
message: 'Syntax Error: Unexpected Name "extend"',
message: 'Syntax Error: Unexpected Name "extend".',
locations: [{ line: 3, column: 7 }],
});

Expand All @@ -242,7 +242,7 @@ describe('Schema Parser', () => {
world: String
}
`).to.deep.equal({
message: 'Syntax Error: Unexpected String "Description"',
message: 'Syntax Error: Unexpected String "Description".',
locations: [{ line: 2, column: 14 }],
});
});
Expand Down Expand Up @@ -300,7 +300,7 @@ describe('Schema Parser', () => {

it('Schema extension without anything throws', () => {
expectSyntaxError('extend schema').to.deep.equal({
message: 'Syntax Error: Unexpected <EOF>',
message: 'Syntax Error: Unexpected <EOF>.',
locations: [{ line: 1, column: 14 }],
});
});
Expand Down Expand Up @@ -724,28 +724,28 @@ describe('Schema Parser', () => {

it('Union fails with no types', () => {
expectSyntaxError('union Hello = |').to.deep.equal({
message: 'Syntax Error: Expected Name, found <EOF>',
message: 'Syntax Error: Expected Name, found <EOF>.',
locations: [{ line: 1, column: 16 }],
});
});

it('Union fails with leading double pipe', () => {
expectSyntaxError('union Hello = || Wo | Rld').to.deep.equal({
message: 'Syntax Error: Expected Name, found |',
message: 'Syntax Error: Expected Name, found "|".',
locations: [{ line: 1, column: 16 }],
});
});

it('Union fails with double pipe', () => {
expectSyntaxError('union Hello = Wo || Rld').to.deep.equal({
message: 'Syntax Error: Expected Name, found |',
message: 'Syntax Error: Expected Name, found "|".',
locations: [{ line: 1, column: 19 }],
});
});

it('Union fails with trailing pipe', () => {
expectSyntaxError('union Hello = | Wo | Rld |').to.deep.equal({
message: 'Syntax Error: Expected Name, found <EOF>',
message: 'Syntax Error: Expected Name, found <EOF>.',
locations: [{ line: 1, column: 27 }],
});
});
Expand Down Expand Up @@ -803,7 +803,7 @@ input Hello {
world(foo: Int): String
}
`).to.deep.equal({
message: 'Syntax Error: Expected :, found (',
message: 'Syntax Error: Expected ":", found "(".',
locations: [{ line: 3, column: 14 }],
});
});
Expand Down Expand Up @@ -884,7 +884,7 @@ input Hello {
expectSyntaxError(
'directive @foo on FIELD | INCORRECT_LOCATION',
).to.deep.equal({
message: 'Syntax Error: Unexpected Name "INCORRECT_LOCATION"',
message: 'Syntax Error: Unexpected Name "INCORRECT_LOCATION".',
locations: [{ line: 1, column: 27 }],
});
});
Expand All @@ -896,7 +896,7 @@ input Hello {
it('Option: allowLegacySDLEmptyFields supports type with empty fields', () => {
const body = 'type Hello { }';
expectSyntaxError(body).to.include({
message: 'Syntax Error: Expected Name, found }',
message: 'Syntax Error: Expected Name, found "}".',
});

const doc = parse(body, { allowLegacySDLEmptyFields: true });
Expand All @@ -906,7 +906,7 @@ input Hello {
it('Option: allowLegacySDLImplementsInterfaces', () => {
const body = 'type Hello implements Wo rld { field: String }';
expectSyntaxError(body).to.include({
message: 'Syntax Error: Unexpected Name "rld"',
message: 'Syntax Error: Unexpected Name "rld".',
});

const doc = parse(body, { allowLegacySDLImplementsInterfaces: true });
Expand Down
3 changes: 1 addition & 2 deletions src/language/lexer.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,7 @@ export type Lexer<TOptions> = {
};

// @internal
export function isPunctuatorToken(token: Token) {
const kind = token.kind;
export function isPunctuatorTokenKind(kind: TokenKindEnum) {
return (
kind === TokenKind.BANG ||
kind === TokenKind.DOLLAR ||
Expand Down
20 changes: 14 additions & 6 deletions src/language/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { type GraphQLError } from '../error/GraphQLError';

import { Kind } from './kinds';
import { Source } from './source';
import { type Lexer, createLexer } from './lexer';
import { DirectiveLocation } from './directiveLocation';
import { type TokenKindEnum, TokenKind } from './tokenKind';
import { type Lexer, createLexer, isPunctuatorTokenKind } from './lexer';
import {
type Location,
type Token,
Expand Down Expand Up @@ -1418,7 +1418,7 @@ class Parser {
throw syntaxError(
this._lexer.source,
token.start,
`Expected ${kind}, found ${getTokenDesc(token)}`,
`Expected ${getTokenKindDesc(kind)}, found ${getTokenDesc(token)}.`,
);
}

Expand Down Expand Up @@ -1447,7 +1447,7 @@ class Parser {
throw syntaxError(
this._lexer.source,
token.start,
`Expected "${value}", found ${getTokenDesc(token)}`,
`Expected "${value}", found ${getTokenDesc(token)}.`,
);
}
}
Expand All @@ -1474,7 +1474,7 @@ class Parser {
return syntaxError(
this._lexer.source,
token.start,
`Unexpected ${getTokenDesc(token)}`,
`Unexpected ${getTokenDesc(token)}.`,
);
}

Expand Down Expand Up @@ -1556,6 +1556,14 @@ defineToJSON(Loc, function() {
* A helper function to describe a token as a string for debugging
*/
function getTokenDesc(token: Token): string {
const value = token.value;
return value ? `${token.kind} "${value}"` : token.kind;
return (
getTokenKindDesc(token.kind) + (token.value ? ` "${token.value}"` : '')
);
}

/**
* A helper function to describe a token kind as a string for debugging
*/
function getTokenKindDesc(kind: TokenKindEnum): string {
return isPunctuatorTokenKind(kind) ? `"${kind}"` : kind;
}
4 changes: 2 additions & 2 deletions src/utilities/stripIgnoredCharacters.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import inspect from '../jsutils/inspect';

import { Source } from '../language/source';
import { TokenKind } from '../language/tokenKind';
import { createLexer, isPunctuatorToken } from '../language/lexer';
import { createLexer, isPunctuatorTokenKind } from '../language/lexer';
import {
dedentBlockStringValue,
getBlockStringIndentation,
Expand Down Expand Up @@ -84,7 +84,7 @@ export function stripIgnoredCharacters(source: string | Source): string {
* Also prevent case of non-punctuator token following by spread resulting
* in invalid token (e.g. `1...` is invalid Float token).
*/
const isNonPunctuator = !isPunctuatorToken(currentToken);
const isNonPunctuator = !isPunctuatorTokenKind(currentToken.kind);
if (wasLastAddedTokenNonPunctuator) {
if (isNonPunctuator || currentToken.kind === TokenKind.SPREAD) {
strippedBody += ' ';
Expand Down