diff --git a/src/error/syntaxError.js b/src/error/syntaxError.js index e9777f3bed..89ef08535b 100644 --- a/src/error/syntaxError.js +++ b/src/error/syntaxError.js @@ -12,6 +12,8 @@ import { getLocation } from '../language/location'; import type { Source } from '../language/source'; import { GraphQLError } from './GraphQLError'; +import type {SourceLocation} from '../language/location'; + /** * Produces a GraphQLError representing a syntax error, containing useful * descriptive information about the syntax error's position in the source. @@ -23,7 +25,8 @@ export function syntaxError( ): GraphQLError { const location = getLocation(source, position); const line = location.line + source.locationOffset.line - 1; - const column = location.column + source.locationOffset.column - 1; + const columnOffset = getColumnOffset(source, location); + const column = location.column + columnOffset; const error = new GraphQLError( `Syntax Error ${source.name} (${line}:${column}) ${description}` + '\n\n' + highlightSourceAtLocation(source, location), @@ -41,14 +44,14 @@ export function syntaxError( function highlightSourceAtLocation(source, location) { const line = location.line; const lineOffset = source.locationOffset.line - 1; - const columnOffset = source.locationOffset.column - 1; + const columnOffset = getColumnOffset(source, location); const contextLine = line + lineOffset; const prevLineNum = (contextLine - 1).toString(); const lineNum = contextLine.toString(); const nextLineNum = (contextLine + 1).toString(); const padLen = nextLineNum.length; const lines = source.body.split(/\r\n|[\n\r]/g); - lines[0] = whitespace(columnOffset) + lines[0]; + lines[0] = whitespace(source.locationOffset.column - 1) + lines[0]; return ( (line >= 2 ? lpad(padLen, prevLineNum) + ': ' + lines[line - 2] + '\n' : '') + @@ -59,6 +62,13 @@ function highlightSourceAtLocation(source, location) { ); } +function getColumnOffset( + source: Source, + location: SourceLocation +): number { + return location.line === 1 ? source.locationOffset.column - 1 : 0; +} + function whitespace(len) { return Array(len + 1).join(' '); } diff --git a/src/language/__tests__/lexer-test.js b/src/language/__tests__/lexer-test.js index ad2b24e0d8..cd4c9f5da7 100644 --- a/src/language/__tests__/lexer-test.js +++ b/src/language/__tests__/lexer-test.js @@ -127,7 +127,7 @@ describe('Lexer', () => { '\n' + ' ?\n' + '\n'; - const source = new Source(str, 'foo.js', { line: 11, column: 1 }); + const source = new Source(str, 'foo.js', { line: 11, column: 12 }); return createLexer(source).advance(); }).to.throw( 'Syntax Error foo.js (13:6) ' + diff --git a/src/language/location.js b/src/language/location.js index c7b2db1d84..7e724b6606 100644 --- a/src/language/location.js +++ b/src/language/location.js @@ -13,7 +13,7 @@ import type { Source } from './source'; /** * Represents a location in a Source. */ -type SourceLocation = { +export type SourceLocation = { line: number; column: number; };