From e2dce36b53e0ae23a3b244cd9da45e3ed2b40a57 Mon Sep 17 00:00:00 2001 From: Rob Wise Date: Fri, 7 Jul 2017 11:53:35 -0400 Subject: [PATCH] fix(handleError): properly handle alternative loc in Prettier errors Prettier sometimes provides a different API for the `loc` property on the errors it throws. We were only anticipating one type, where there is a `start` property nested in `loc`, but there's actually another where the line and column are direct children of `loc` and there is no `start` property. We now will properly handle either case. Fixes #229 --- decls/index.js | 3 +-- dist/executePrettier/handleError.js | 10 ++++++++- src/executePrettier/handleError.js | 11 ++++++---- src/executePrettier/handleError.test.js | 29 +++++++++++++++++++++++-- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/decls/index.js b/decls/index.js index 1778900a..53a035d2 100644 --- a/decls/index.js +++ b/decls/index.js @@ -89,7 +89,7 @@ declare type Linter$Message$ApplySolution = { }; // eslint-disable-next-line no-undef declare type Prettier$SyntaxError = { - loc: { start: { line: number, column: number } }, + loc: { start: { line: number, column: number } } | {| line: number, column: number |}, message: string, }; declare type Linter$Message = { @@ -136,5 +136,4 @@ declare type Linter$IndieDelegate = { setAllMessages: (messages: Array) => void, onDidUpdate: (callback: Function) => Atom$Disposable, onDidDestroy: (callback: Function) => Atom$Disposable, - dispose: () => void, }; diff --git a/dist/executePrettier/handleError.js b/dist/executePrettier/handleError.js index 4ae9385a..0e19d31b 100644 --- a/dist/executePrettier/handleError.js +++ b/dist/executePrettier/handleError.js @@ -11,9 +11,17 @@ var _require2 = require('../helpers'), createPoint = _require2.createPoint, createRange = _require2.createRange; +var errorLine = function errorLine(error) { + return error.loc.start ? error.loc.start.line : error.loc.line; +}; + +var errorColumn = function errorColumn(error) { + return error.loc.start ? error.loc.start.column : error.loc.column; +}; + // NOTE: Prettier error locations are not zero-based (i.e., they start at 1) var buildPointArrayFromPrettierErrorAndRange = function buildPointArrayFromPrettierErrorAndRange(error, bufferRange) { - return createPoint(error.loc.start.line + bufferRange.start.row - 1, error.loc.start.line === 0 ? error.loc.start.column + bufferRange.start.column - 1 : error.loc.start.column - 1); + return createPoint(errorLine(error) + bufferRange.start.row - 1, errorLine(error) === 0 ? errorColumn(error) + bufferRange.start.column - 1 : errorColumn(error) - 1); }; var buildExcerpt = function buildExcerpt(error) { diff --git a/src/executePrettier/handleError.js b/src/executePrettier/handleError.js index e3942406..c63e0587 100644 --- a/src/executePrettier/handleError.js +++ b/src/executePrettier/handleError.js @@ -10,13 +10,16 @@ type HandleErrorArgs = { bufferRange: Range, }; +const errorLine = (error: Prettier$SyntaxError) => (error.loc.start ? error.loc.start.line : error.loc.line); + +const errorColumn = (error: Prettier$SyntaxError) => + error.loc.start ? error.loc.start.column : error.loc.column; + // NOTE: Prettier error locations are not zero-based (i.e., they start at 1) const buildPointArrayFromPrettierErrorAndRange = (error: Prettier$SyntaxError, bufferRange: Range): Point => createPoint( - error.loc.start.line + bufferRange.start.row - 1, - error.loc.start.line === 0 - ? error.loc.start.column + bufferRange.start.column - 1 - : error.loc.start.column - 1, + errorLine(error) + bufferRange.start.row - 1, + errorLine(error) === 0 ? errorColumn(error) + bufferRange.start.column - 1 : errorColumn(error) - 1, ); const buildExcerpt = (error: Prettier$SyntaxError) => /(.*)\s\(\d+:\d+\).*/.exec(error.message)[1]; diff --git a/src/executePrettier/handleError.test.js b/src/executePrettier/handleError.test.js index a1ede931..4f0e1341 100644 --- a/src/executePrettier/handleError.test.js +++ b/src/executePrettier/handleError.test.js @@ -7,9 +7,13 @@ const { createRange } = require('../helpers'); const handleError = require('./handleError'); // helpers -const buildFakeError = ({ line, column }) => { +const buildFakeError = ({ line, column }, useAlternativeErrorApi = false) => { const error = new Error(`Unexpected token (${line}:${column}) | stack trace`); - error.loc = { start: { line, column } }; + if (useAlternativeErrorApi) { + error.loc = { line, column }; + } else { + error.loc = { start: { line, column } }; + } return error; }; @@ -39,6 +43,27 @@ it('sets an error message in the indie-linter', () => { expect(linterInterface.setMessages).toHaveBeenCalledWith(editor, expectedMessages); }); +it('works with the alternative error location API from Prettier', () => { + getCurrentFilePath.mockImplementation(() => '/fake/file/path.js'); + const error = buildFakeError({ line: 1, column: 2 }, true); + const editor = null; + const bufferRange = { start: { row: 0, column: 0 }, end: { row: 0, column: 0 } }; + + handleError({ bufferRange, editor, error }); + + const expectedMessages = [ + { + location: { + file: '/fake/file/path.js', + position: createRange([0, 1], [0, 1]), + }, + excerpt: 'Unexpected token', + severity: 'error', + }, + ]; + expect(linterInterface.setMessages).toHaveBeenCalledWith(editor, expectedMessages); +}); + describe('position property of the message sent to the linter', () => { it('accounts for the start row of the buffer range', () => { const editor = null;