Skip to content

Commit

Permalink
Use error ctor for syntax errors rather than mutation
Browse files Browse the repository at this point in the history
Fixes issue where syntax errors were reported with poor messages.
  • Loading branch information
leebyron committed Aug 14, 2015
1 parent a4c5605 commit 60d0cbb
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 38 deletions.
72 changes: 39 additions & 33 deletions src/error/GraphQLError.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,58 +10,64 @@

import { getLocation } from '../language';
import type { Node } from '../language/ast';
import type { Source } from '../language/source';


export class GraphQLError extends Error {
message: string;
stack: string;
nodes: ?Array<Node>;
source: any;
positions: any;
source: Source;
positions: Array<number>;
locations: any;

constructor(
message: string,
// A flow bug keeps us from declaring nodes as an array of Node
nodes?: Array<any/* Node */>,
stack?: ?string
stack?: ?string,
source?: Source,
positions?: Array<number>
) {
super(message);
this.message = message;

Object.defineProperty(this, 'stack', { value: stack || message });
Object.defineProperty(this, 'nodes', { value: nodes });
}
}

// Note: flow does not yet know about Object.defineProperty with `get`.
Object.defineProperty(GraphQLError.prototype, 'source', ({
get() {
var nodes = this.nodes;
if (nodes && nodes.length > 0) {
var node = nodes[0];
return node && node.loc && node.loc.source;
}
}
}: any));
// Note: flow does not yet know about Object.defineProperty with `get`.
Object.defineProperty(this, 'source', ({
get() {
if (source) {
return source;
}
if (nodes && nodes.length > 0) {
var node = nodes[0];
return node && node.loc && node.loc.source;
}
}
}: any));

Object.defineProperty(GraphQLError.prototype, 'positions', ({
get() {
var nodes = this.nodes;
if (nodes) {
var positions = nodes.map(node => node.loc && node.loc.start);
if (positions.some(p => p)) {
return positions;
Object.defineProperty(this, 'positions', ({
get() {
if (positions) {
return positions;
}
if (nodes) {
var nodePositions = nodes.map(node => node.loc && node.loc.start);
if (nodePositions.some(p => p)) {
return nodePositions;
}
}
}
}
}
}: any));
}: any));

Object.defineProperty(GraphQLError.prototype, 'locations', ({
get() {
var positions = this.positions;
var source = this.source;
if (positions && source) {
return positions.map(pos => getLocation(source, pos));
}
Object.defineProperty(this, 'locations', ({
get() {
if (this.positions && this.source) {
return this.positions.map(pos => getLocation(this.source, pos));
}
}
}: any));
}
}: any));
}
10 changes: 5 additions & 5 deletions src/error/syntaxError.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ export function syntaxError(
var location = getLocation(source, position);
var error = new GraphQLError(
`Syntax Error ${source.name} (${location.line}:${location.column}) ` +
description + '\n\n' + highlightSourceAtLocation(source, location)
description + '\n\n' + highlightSourceAtLocation(source, location),
undefined,
undefined,
source,
[ position ]
);
error.nodes = null;
error.positions = [ position ];
error.locations = [ location ];
error.source = source;
return error;
}

Expand Down
21 changes: 21 additions & 0 deletions src/language/__tests__/parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,27 @@ describe('Parser', () => {

it('parse provides useful errors', () => {

var caughtError;
try {
parse('{');
} catch (error) {
caughtError = error;
}

expect(caughtError.message).to.equal(
`Syntax Error GraphQL (1:2) Expected Name, found EOF
1: {
^
`
);

expect(caughtError.positions).to.deep.equal([ 1 ]);

expect(caughtError.locations).to.deep.equal([
{ line: 1, column: 2 }
]);

expect(
() => parse(
`{ ...MissingOn }
Expand Down

0 comments on commit 60d0cbb

Please sign in to comment.