diff --git a/CHANGELOG.md b/CHANGELOG.md index ca5ca14..b452046 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ # Change log ### vNEXT +- Fix error location information for literal .graphql files and strings with leading newlines in [#122](https://github.com/apollographql/eslint-plugin-graphql/pull/122) by [Dan Freeman](https://github.com/dfreeman) ### v2.1.0 - Retrieves `.graphqlconfig` relative to the file being linted, which re-enables support for `vscode-eslint` using `.graphqlconfig` in [#108](https://github.com/apollographql/eslint-plugin-graphql/pull/108) by [Jon Wong][https://github.com/jnwng/] diff --git a/src/index.js b/src/index.js index 98bcef5..039ad79 100644 --- a/src/index.js +++ b/src/index.js @@ -418,11 +418,11 @@ function locFrom(node, error) { let line; let column; - if (location.line === 1) { + if (location.line === 1 && node.tag.name !== internalTag) { line = node.loc.start.line; - column = node.loc.start.col + location.col; + column = node.tag.loc.end.column + location.column; } else { - line = node.loc.start.line + location.line; + line = node.loc.start.line + location.line - 1; column = location.column - 1; } @@ -489,7 +489,7 @@ function replaceExpressions(node, context, env) { } }); - return chunks.join('').trim(); + return chunks.join(''); } function strWithLen(len) { diff --git a/test/__fixtures__/required-fields-invalid-no-id.graphql b/test/__fixtures__/required-fields-invalid-no-id.graphql index 751a134..3a7de62 100644 --- a/test/__fixtures__/required-fields-invalid-no-id.graphql +++ b/test/__fixtures__/required-fields-invalid-no-id.graphql @@ -1 +1,5 @@ -query { greetings { hello } } +query { + greetings { + hello + } +} diff --git a/test/makeProcessors.js b/test/makeProcessors.js index ebc1dbe..0877cb0 100644 --- a/test/makeProcessors.js +++ b/test/makeProcessors.js @@ -93,5 +93,35 @@ describe('processors', () => { }); }); }); + + describe('error line/column locations', () => { + it('populates correctly for a single-line document', () => { + const results = execute('required-fields-invalid-array'); + assert.equal(results.errorCount, 1); + assert.deepEqual(results.results[0].messages[0], { + column: 9, + line: 1, + message: "'id' field required on 'stories'", + nodeType: 'TaggedTemplateExpression', + ruleId: 'graphql/required-fields', + severity: 2, + source: 'ESLintPluginGraphQLFile`query { stories { comments { text } } }' + }); + }); + + it('populates correctly for a multi-line document', () => { + const results = execute('required-fields-invalid-no-id'); + assert.equal(results.errorCount, 1); + assert.deepEqual(results.results[0].messages[0], { + column: 3, + line: 2, + message: "'id' field required on 'greetings'", + nodeType: 'TaggedTemplateExpression', + ruleId: 'graphql/required-fields', + severity: 2, + source: ' greetings {' + }); + }); + }); }); }); diff --git a/test/makeRule.js b/test/makeRule.js index 94a431c..449e4d4 100644 --- a/test/makeRule.js +++ b/test/makeRule.js @@ -73,10 +73,12 @@ const parserOptions = { { options, parserOptions, - code: 'const x = gql`{ nonExistentQuery }`', + code: 'const x = gql`\n query {\n nonExistentQuery\n }\n`', errors: [{ message: 'Cannot query field "nonExistentQuery" on type "Query".', - type: 'TaggedTemplateExpression' + type: 'TaggedTemplateExpression', + line: 3, + column: 5 }] }, {