Skip to content

Commit fa6ee06

Browse files
committed
Allows buildASTSchema to throw errors with source locations.
1 parent f7b94d1 commit fa6ee06

File tree

2 files changed

+35
-7
lines changed

2 files changed

+35
-7
lines changed

src/error/syntaxError.js

+21
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import { getLocation } from '../language/location';
1212
import type { Source } from '../language/source';
1313
import { GraphQLError } from './GraphQLError';
14+
import type { ASTNode } from '../language/ast';
1415

1516
/**
1617
* Produces a GraphQLError representing a syntax error, containing useful
@@ -32,6 +33,26 @@ export function syntaxError(
3233
return error;
3334
}
3435

36+
/**
37+
* Produces a string for the invarant(...) function that renders the location
38+
* where an error occurred. If no source is passed in, it renders the message
39+
* without context.
40+
*/
41+
export function invariantError(
42+
message: string,
43+
node: ASTNode,
44+
source: ?Source
45+
): string {
46+
const position = node.loc ? node.loc.start : null;
47+
if (position != null && source != null) {
48+
const location = getLocation(source, position);
49+
return `${message} (${location.line}:${location.column}) ` +
50+
'\n\n' + highlightSourceAtLocation(source, location);
51+
} else {
52+
return message;
53+
}
54+
}
55+
3556
/**
3657
* Render a helpful description of the location of the error in the GraphQL
3758
* Source document.

src/utilities/buildASTSchema.js

+14-7
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@ import invariant from '../jsutils/invariant';
1313
import keyValMap from '../jsutils/keyValMap';
1414
import { valueFromAST } from './valueFromAST';
1515
import { TokenKind } from '../language/lexer';
16+
import { getLocation } from '../language/location';
1617
import { parse } from '../language/parser';
17-
import type { Source } from '../language/source';
18+
import { Source } from '../language/source';
1819
import { getArgumentValues } from '../execution/values';
20+
import { invariantError } from '../error/syntaxError';
1921

2022
import {
2123
LIST_TYPE,
@@ -135,7 +137,7 @@ function getNamedTypeNode(typeNode: TypeNode): NamedTypeNode {
135137
* Given that AST it constructs a GraphQLSchema. The resulting schema
136138
* has no resolve methods, so execution will use default resolvers.
137139
*/
138-
export function buildASTSchema(ast: DocumentNode): GraphQLSchema {
140+
export function buildASTSchema(ast: DocumentNode, source?: Source): GraphQLSchema {
139141
if (!ast || ast.kind !== DOCUMENT) {
140142
throw new Error('Must provide a document ast.');
141143
}
@@ -300,25 +302,29 @@ export function buildASTSchema(ast: DocumentNode): GraphQLSchema {
300302

301303
function produceInputType(typeNode: TypeNode): GraphQLInputType {
302304
const type = produceType(typeNode);
303-
invariant(isInputType(type), 'Expected Input type.');
305+
invariant(isInputType(type),
306+
invariantError('Expected Input type', typeNode, source));
304307
return (type: any);
305308
}
306309

307310
function produceOutputType(typeNode: TypeNode): GraphQLOutputType {
308311
const type = produceType(typeNode);
309-
invariant(isOutputType(type), 'Expected Output type.');
312+
invariant(isOutputType(type),
313+
invariantError('Expected Output type', typeNode, source));
310314
return (type: any);
311315
}
312316

313317
function produceObjectType(typeNode: TypeNode): GraphQLObjectType {
314318
const type = produceType(typeNode);
315-
invariant(type instanceof GraphQLObjectType, 'Expected Object type.');
319+
invariant(type instanceof GraphQLObjectType,
320+
invariantError('Expected Object type', typeNode, source));
316321
return type;
317322
}
318323

319324
function produceInterfaceType(typeNode: TypeNode): GraphQLInterfaceType {
320325
const type = produceType(typeNode);
321-
invariant(type instanceof GraphQLInterfaceType, 'Expected Interface type.');
326+
invariant(type instanceof GraphQLInterfaceType,
327+
invariantError('Expected Interface type', typeNode, source));
322328
return type;
323329
}
324330

@@ -518,7 +524,8 @@ export function getDescription(node: { loc?: Location }): ?string {
518524
* document.
519525
*/
520526
export function buildSchema(source: string | Source): GraphQLSchema {
521-
return buildASTSchema(parse(source));
527+
const sourceObj = typeof source === 'string' ? new Source(source) : source;
528+
return buildASTSchema(parse(sourceObj), sourceObj);
522529
}
523530

524531
// Count the number of spaces on the starting side of a string.

0 commit comments

Comments
 (0)