Repository: prettier/prettier-atom (js)

Issue:
Uncaught TypeError: Cannot read property 'start' of undefined
[Enter steps to reproduce:]

1. Open Javascript file
2. Select text
3. Select "format with prettier" from context menu

**Atom**: 1.18.0 x64
**Electron**: 1.3.15
**OS**: Mac OS X 10.12.5
**Thrown From**: [prettier-atom](https://github.com/prettier/prettier-atom) package 0.36.1


### Stack Trace

Uncaught TypeError: Cannot read property 'start' of undefined

```
At /Users/jesse/.atom/packages/prettier-atom/dist/executePrettier/handleError.js:15

TypeError: Cannot read property 'start' of undefined
    at errorLine (/packages/prettier-atom/dist/executePrettier/handleError.js:15:19)
    at buildPointArrayFromPrettierErrorAndRange (/packages/prettier-atom/dist/executePrettier/handleError.js:24:22)
    at setErrorMessageInLinter (/packages/prettier-atom/dist/executePrettier/handleError.js:40:29)
    at /packages/prettier-atom/node_modules/lodash/lodash.min.js:49:114
    at executePrettierOnBufferRange (/packages/prettier-atom/dist/executePrettier/executePrettierOnBufferRange.js:45:5)
    at /packages/prettier-atom/dist/manualFormat/index.js:22:12
    at Array.forEach (native)
    at formatSelectedBufferRanges (/packages/prettier-atom/dist/manualFormat/index.js:21:43)
    at /packages/prettier-atom/node_modules/lodash/lodash.min.js:5:165)
    at /packages/prettier-atom/node_modules/lodash/lodash.min.js:97:162
    at /packages/prettier-atom/node_modules/lodash/lodash.min.js:5:165)
    at /packages/prettier-atom/node_modules/lodash/lodash.min.js:63:325
    at /packages/prettier-atom/node_modules/lodash/lodash.min.js:49:144
    at /packages/prettier-atom/dist/main.js:33:15)
    at CommandRegistry.module.exports.CommandRegistry.handleCommandEvent (/Applications/Atom.app/Contents/Resources/app/src/command-registry.js:265:35)
    at CommandRegistry.handleCommandEvent (/Applications/Atom.app/Contents/Resources/app/src/command-registry.js:3:65)
    at CommandRegistry.module.exports.CommandRegistry.dispatch (/Applications/Atom.app/Contents/Resources/app/src/command-registry.js:166:25)
    at AtomEnvironment.module.exports.AtomEnvironment.dispatchContextMenuCommand (/Applications/Atom.app/Contents/Resources/app/src/atom-environment.js:1320:34)
    at EventEmitter.outerCallback (/Applications/Atom.app/Contents/Resources/app/src/application-delegate.js:347:31)
    at emitThree (events.js:116:13)
    at EventEmitter.emit (events.js:194:7)
```

### Commands

```
     -2:43.4.0 core:select-all (input.hidden-input)
     -2:40.8.0 prettier:format (div.line)
     -0:47.3.0 core:confirm (input.hidden-input)
     -0:18.1.0 fuzzy-finder:toggle-file-finder (atom-workspace.workspace.scrollbars-visible-when-scrolling.theme-one-dark-syntax.theme-one-dark-ui)
     -0:16.9.0 core:confirm (input.hidden-input)
     -0:14.4.0 core:select-all (input.hidden-input)
     -0:10.5.0 prettier:format (span.syntax--comment.syntax--line.syntax--double-slash.syntax--js)
```

### Non-Core Packages

```
atom-beautify 0.30.3 
atom-language-velocity 1.1.0 
atom-terminal 0.8.0 
build 0.68.0 
build-gradle 0.6.0 
build-npm-apm 0.12.0 
busy 0.7.0 
busy-signal 1.4.3 
change-case 0.6.5 
editorconfig 2.2.2 
highlight-selected 0.13.1 
intentions 1.1.2 
language-gradle 0.0.3 
language-groovy 0.7.0 
linter 2.2.0 
linter-eslint 8.2.1 
linter-flow 5.6.0 
linter-ui-default 1.6.2 
minimap 4.28.2 
prettier-atom 0.36.1 
sort-lines 0.14.0 
Sublime-Style-Column-Selection 1.7.4 
terminal-plus 0.14.5 
```



Pull request description:
fix(errors): handle errors that aren't syntax errors
Previously, we were assuming all errors thrown during execution of the formatters were going to be
syntax errors. However, this is not the case, so we must handle these errors elegantly by displaying
them in a popup.

Resolves #231

Patch:
diff --git a/decls/index.js b/decls/index.js
index 53a035d..3b2305d 100644
--- a/decls/index.js
+++ b/decls/index.js
@@ -91,6 +91,7 @@ declare type Linter$Message$ApplySolution = {
 declare type Prettier$SyntaxError = {
   loc: { start: { line: number, column: number } } | {| line: number, column: number |},
   message: string,
+  stack: string,
 };
 declare type Linter$Message = {
   // NOTE: These are given by providers
diff --git a/dist/executePrettier/handleError.js b/dist/executePrettier/handleError.js
index 0e19d31..2d5663b 100644
--- a/dist/executePrettier/handleError.js
+++ b/dist/executePrettier/handleError.js
@@ -7,9 +7,12 @@ var _require = require('../editorInterface'),
 
 var linter = require('../linterInterface');
 
-var _require2 = require('../helpers'),
-    createPoint = _require2.createPoint,
-    createRange = _require2.createRange;
+var _require2 = require('../atomInterface'),
+    addErrorNotification = _require2.addErrorNotification;
+
+var _require3 = require('../helpers'),
+    createPoint = _require3.createPoint,
+    createRange = _require3.createRange;
 
 var errorLine = function errorLine(error) {
   return error.loc.start ? error.loc.start.line : error.loc.line;
@@ -44,6 +47,15 @@ var setErrorMessageInLinter = function setErrorMessageInLinter(_ref) {
   }]);
 };
 
-var handleError = _.flow(setErrorMessageInLinter, _.stubFalse);
+var isSyntaxError = _.overSome([_.flow(_.get('error.loc.start.line'), _.isInteger), _.flow(_.get('error.loc.line'), _.isInteger)]);
+
+var displayErrorInPopup = function displayErrorInPopup(args) {
+  return addErrorNotification('prettier-atom failed: ' + args.error.message, {
+    stack: args.error.stack,
+    dismissable: true
+  });
+};
+
+var handleError = _.cond([[isSyntaxError, setErrorMessageInLinter], [_.stubTrue, displayErrorInPopup]]);
 
 module.exports = handleError;
\ No newline at end of file
diff --git a/src/executePrettier/handleError.js b/src/executePrettier/handleError.js
index c63e058..d962310 100644
--- a/src/executePrettier/handleError.js
+++ b/src/executePrettier/handleError.js
@@ -2,6 +2,7 @@
 const _ = require('lodash/fp');
 const { getCurrentFilePath } = require('../editorInterface');
 const linter = require('../linterInterface');
+const { addErrorNotification } = require('../atomInterface');
 const { createPoint, createRange } = require('../helpers');
 
 type HandleErrorArgs = {
@@ -40,6 +41,20 @@ const setErrorMessageInLinter = ({ editor, bufferRange, error }: HandleErrorArgs
     },
   ]);
 
-const handleError: HandleErrorArgs => false = _.flow(setErrorMessageInLinter, _.stubFalse);
+const isSyntaxError: HandleErrorArgs => boolean = _.overSome([
+  _.flow(_.get('error.loc.start.line'), _.isInteger),
+  _.flow(_.get('error.loc.line'), _.isInteger),
+]);
+
+const displayErrorInPopup = (args: HandleErrorArgs) =>
+  addErrorNotification(`prettier-atom failed: ${args.error.message}`, {
+    stack: args.error.stack,
+    dismissable: true,
+  });
+
+const handleError: HandleErrorArgs => void = _.cond([
+  [isSyntaxError, setErrorMessageInLinter],
+  [_.stubTrue, displayErrorInPopup],
+]);
 
 module.exports = handleError;


Test patch:
diff --git a/src/executePrettier/handleError.test.js b/src/executePrettier/handleError.test.js
index 4f0e134..8652f5e 100644
--- a/src/executePrettier/handleError.test.js
+++ b/src/executePrettier/handleError.test.js
@@ -1,8 +1,10 @@
 jest.mock('../editorInterface');
 jest.mock('../linterInterface');
+jest.mock('../atomInterface');
 
 const { getCurrentFilePath } = require('../editorInterface');
 const linterInterface = require('../linterInterface');
+const { addErrorNotification } = require('../atomInterface');
 const { createRange } = require('../helpers');
 const handleError = require('./handleError');
 
@@ -87,3 +89,11 @@ describe('position property of the message sent to the linter', () => {
     expect(positionOfFirstCallOfFirstMessageOfSetMessages()).toEqual(expectedPosition);
   });
 });
+
+it('displays errors in a popup if they are not syntax errors', () => {
+  const error = new Error('fake error');
+
+  handleError({ error });
+
+  expect(addErrorNotification).toHaveBeenCalled();
+});