From f2b1d06aca0d295883d6ee4688f8fa7cc078610e Mon Sep 17 00:00:00 2001 From: Ivan Goncharov Date: Fri, 14 Jun 2019 14:14:42 +0300 Subject: [PATCH 1/2] printLocation: Use vertical bar as number column delimiter --- src/error/__tests__/GraphQLError-test.js | 16 +++++++-------- src/language/__tests__/lexer-test.js | 20 +++++++++---------- src/language/__tests__/parser-test.js | 8 ++++---- src/language/__tests__/printLocation-test.js | 10 +++++----- src/language/printLocation.js | 14 +++++-------- .../__tests__/stripIgnoredCharacters-test.js | 6 +++--- 6 files changed, 35 insertions(+), 39 deletions(-) diff --git a/src/error/__tests__/GraphQLError-test.js b/src/error/__tests__/GraphQLError-test.js index 1a4c720a18..f63feca215 100644 --- a/src/error/__tests__/GraphQLError-test.js +++ b/src/error/__tests__/GraphQLError-test.js @@ -217,16 +217,16 @@ describe('printError', () => { Example error with two nodes SourceA:2:10 - 1: type Foo { - 2: field: String - ^ - 3: } + 1 | type Foo { + 2 | field: String + | ^ + 3 | } SourceB:2:10 - 1: type Foo { - 2: field: Int - ^ - 3: } + 1 | type Foo { + 2 | field: Int + | ^ + 3 | } `); }); }); diff --git a/src/language/__tests__/lexer-test.js b/src/language/__tests__/lexer-test.js index c59057a8db..2ad6c7987b 100644 --- a/src/language/__tests__/lexer-test.js +++ b/src/language/__tests__/lexer-test.js @@ -122,10 +122,10 @@ describe('Lexer', () => { Syntax Error: Cannot parse the unexpected character "?". GraphQL request:3:5 - 2: - 3: ? - ^ - 4: + 2 | + 3 | ? + | ^ + 4 | `); }); @@ -142,10 +142,10 @@ describe('Lexer', () => { Syntax Error: Cannot parse the unexpected character "?". foo.js:13:6 - 12: - 13: ? - ^ - 14: + 12 | + 13 | ? + | ^ + 14 | `); }); @@ -161,8 +161,8 @@ describe('Lexer', () => { Syntax Error: Cannot parse the unexpected character "?". foo.js:1:5 - 1: ? - ^ + 1 | ? + | ^ `); }); diff --git a/src/language/__tests__/parser-test.js b/src/language/__tests__/parser-test.js index 5eb2f26685..dbc68aa651 100644 --- a/src/language/__tests__/parser-test.js +++ b/src/language/__tests__/parser-test.js @@ -48,8 +48,8 @@ describe('Parser', () => { Syntax Error: Expected Name, found GraphQL request:1:2 - 1: { - ^ + 1 | { + | ^ `); expectSyntaxError( @@ -85,8 +85,8 @@ describe('Parser', () => { Syntax Error: Expected {, found MyQuery.graphql:1:6 - 1: query - ^ + 1 | query + | ^ `); }); diff --git a/src/language/__tests__/printLocation-test.js b/src/language/__tests__/printLocation-test.js index 80e1b490cf..1d325fcb0f 100644 --- a/src/language/__tests__/printLocation-test.js +++ b/src/language/__tests__/printLocation-test.js @@ -16,8 +16,8 @@ describe('printLocation', () => { expect(result + '\n').to.equal(dedent` Test:9:1 - 9: * - ^ + 9 | * + | ^ `); }); @@ -29,9 +29,9 @@ describe('printLocation', () => { expect(result + '\n').to.equal(dedent` Test:9:1 - 9: * - ^ - 10: + 9 | * + | ^ + 10 | `); }); }); diff --git a/src/language/printLocation.js b/src/language/printLocation.js index 69b1928e2a..2bc8ea42f2 100644 --- a/src/language/printLocation.js +++ b/src/language/printLocation.js @@ -36,10 +36,10 @@ export function printSourceLocation( `${source.name}:${lineNum}:${columnNum}\n` + printPrefixedLines([ // Lines specified like this: ["prefix", "string"], - [`${lineNum - 1}: `, lines[lineIndex - 1]], - [`${lineNum}: `, lines[lineIndex]], + [`${lineNum - 1}`, lines[lineIndex - 1]], + [`${lineNum}`, lines[lineIndex]], ['', whitespace(columnNum - 1) + '^'], - [`${lineNum + 1}: `, lines[lineIndex + 1]], + [`${lineNum + 1}`, lines[lineIndex + 1]], ]) ); } @@ -47,13 +47,9 @@ export function printSourceLocation( function printPrefixedLines(lines: Array<[string, string]>): string { const existingLines = lines.filter(([_, line]) => line !== undefined); - let padLen = 0; - for (const [prefix] of existingLines) { - padLen = Math.max(padLen, prefix.length); - } - + const padLen = Math.max(...existingLines.map(([prefix]) => prefix.length)); return existingLines - .map(([prefix, line]) => lpad(padLen, prefix) + line) + .map(([prefix, line]) => lpad(padLen, prefix) + ' | ' + line) .join('\n'); } diff --git a/src/utilities/__tests__/stripIgnoredCharacters-test.js b/src/utilities/__tests__/stripIgnoredCharacters-test.js index 2b072efc20..35c9f6cf13 100644 --- a/src/utilities/__tests__/stripIgnoredCharacters-test.js +++ b/src/utilities/__tests__/stripIgnoredCharacters-test.js @@ -157,9 +157,9 @@ describe('stripIgnoredCharacters', () => { Syntax Error: Unterminated string. GraphQL request:1:13 - 1: { foo(arg: " - ^ - 2: " + 1 | { foo(arg: " + | ^ + 2 | " `); }); From 8a764b1aff7dd97c0b4d95b5764b04c4b4ebf543 Mon Sep 17 00:00:00 2001 From: Ivan Goncharov Date: Fri, 14 Jun 2019 17:30:35 +0300 Subject: [PATCH 2/2] printLocation: Add special support for minified documents --- src/language/__tests__/printLocation-test.js | 43 +++++++++++++++++++- src/language/printLocation.js | 27 +++++++++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/language/__tests__/printLocation-test.js b/src/language/__tests__/printLocation-test.js index 1d325fcb0f..129a872a52 100644 --- a/src/language/__tests__/printLocation-test.js +++ b/src/language/__tests__/printLocation-test.js @@ -7,7 +7,48 @@ import dedent from '../../jsutils/dedent'; import { Source } from '../../language'; import { printSourceLocation } from '../printLocation'; -describe('printLocation', () => { +describe('printSourceLocation', () => { + it('prints minified documents', () => { + const minifiedSource = new Source( + 'query SomeMiniFiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String){someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD...on THIRD_ERROR_HERE}}}', + ); + + const firstLocation = printSourceLocation(minifiedSource, { + line: 1, + column: minifiedSource.body.indexOf('FIRST_ERROR_HERE') + 1, + }); + expect(firstLocation + '\n').to.equal(dedent` + GraphQL request:1:53 + 1 | query SomeMiniFiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String) + | ^ + | {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD. + `); + + const secondLocation = printSourceLocation(minifiedSource, { + line: 1, + column: minifiedSource.body.indexOf('SECOND_ERROR_HERE') + 1, + }); + expect(secondLocation + '\n').to.equal(dedent` + GraphQL request:1:114 + 1 | query SomeMiniFiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String) + | {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD. + | ^ + | ..on THIRD_ERROR_HERE}}} + `); + + const thirdLocation = printSourceLocation(minifiedSource, { + line: 1, + column: minifiedSource.body.indexOf('THIRD_ERROR_HERE') + 1, + }); + expect(thirdLocation + '\n').to.equal(dedent` + GraphQL request:1:166 + 1 | query SomeMiniFiedQueryWithErrorInside($foo:String!=FIRST_ERROR_HERE$bar:String) + | {someField(foo:$foo bar:$bar baz:SECOND_ERROR_HERE){fieldA fieldB{fieldC fieldD. + | ..on THIRD_ERROR_HERE}}} + | ^ + `); + }); + it('prints single digit line number with no padding', () => { const result = printSourceLocation( new Source('*', 'Test', { line: 9, column: 1 }), diff --git a/src/language/printLocation.js b/src/language/printLocation.js index 2bc8ea42f2..7cff1602fb 100644 --- a/src/language/printLocation.js +++ b/src/language/printLocation.js @@ -30,14 +30,37 @@ export function printSourceLocation( const columnOffset = sourceLocation.line === 1 ? firstLineColumnOffset : 0; const columnNum = sourceLocation.column + columnOffset; + const locationStr = `${source.name}:${lineNum}:${columnNum}\n`; const lines = body.split(/\r\n|[\n\r]/g); + const locationLine = lines[lineIndex]; + + // Special case for minified documents + if (locationLine.length > 120) { + const sublineIndex = Math.floor(columnNum / 80); + const sublineColumnNum = columnNum % 80; + const sublines = []; + for (let i = 0; i < locationLine.length; i += 80) { + sublines.push(locationLine.slice(i, i + 80)); + } + + return ( + locationStr + + printPrefixedLines([ + [`${lineNum}`, sublines[0]], + ...sublines.slice(1, sublineIndex + 1).map(subline => ['', subline]), + [' ', whitespace(sublineColumnNum - 1) + '^'], + ['', sublines[sublineIndex + 1]], + ]) + ); + } + return ( - `${source.name}:${lineNum}:${columnNum}\n` + + locationStr + printPrefixedLines([ // Lines specified like this: ["prefix", "string"], [`${lineNum - 1}`, lines[lineIndex - 1]], - [`${lineNum}`, lines[lineIndex]], + [`${lineNum}`, locationLine], ['', whitespace(columnNum - 1) + '^'], [`${lineNum + 1}`, lines[lineIndex + 1]], ])