Repository: prettier/prettier-atom
Pull request #132 (2017-04-17 16:22:54)

Add a prettier:debug command
Users often create issues without providing enough details to help maintainers understand their problems.

This adds a `prettier:debug` command that displays info about the current installation of `prettier-atom`: versions, detailed configuration...
Got the idea from [linter-eslint](https://github.com/AtomLinter/linter-eslint).

Here's how it looks:
![prettier:debug example](https://i.imgur.com/dbPN732.png)

I also added an issue template to offer some guidance, including using this new command (`CONTRIBUTING.md` doesn't say anything about creating issues).


Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index de9a501..683407c 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -141,7 +141,8 @@
       "avatar_url": "https://avatars0.githubusercontent.com/u/11488612?v=3",
       "profile": "https://github.com/darahak",
       "contributions": [
-        "code"
+        "code",
+        "doc"
       ]
     },
     {
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 0000000..8f340ab
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,11 @@
+<!-- Describe your issue here with as many details as possible -->
+
+<!--
+Paste the output of the `Prettier: Debug` command below.
+Protip: you can use a <details> tag to hide or show really large elements.
+
+For example:
+<details>
+  A really long text
+</details>
+-->
diff --git a/README.md b/README.md
index d7695e6..4e9f9b3 100644
--- a/README.md
+++ b/README.md
@@ -55,7 +55,7 @@ Thanks goes to these people ([emoji key][emojis]):
 <!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
 | [<img src="https://avatars.githubusercontent.com/u/17031?v=3" width="100px;"/><br /><sub>James Long</sub>](http://jlongster.com)<br />💬 [💻](https://github.com/prettier/prettier-atom/commits?author=jlongster) [📖](https://github.com/prettier/prettier-atom/commits?author=jlongster) 🔌 👀 | [<img src="https://avatars.githubusercontent.com/u/6173488?v=3" width="100px;"/><br /><sub>Rob Wise</sub>](https://robwise.github.io)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=robwise) [📖](https://github.com/prettier/prettier-atom/commits?author=robwise) 💬 💡 👀 [⚠️](https://github.com/prettier/prettier-atom/commits?author=robwise) | [<img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;"/><br /><sub>Kent C. Dodds</sub>](https://kentcdodds.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=kentcdodds) [📖](https://github.com/prettier/prettier-atom/commits?author=kentcdodds) 🚇 | [<img src="https://avatars.githubusercontent.com/u/1144075?v=3" width="100px;"/><br /><sub>Luca Barone</sub>](https://github.com/cloud-walker)<br /> | [<img src="https://avatars.githubusercontent.com/u/4514159?v=3" width="100px;"/><br /><sub>Arnar Þór Sveinsson</sub>](https://github.com/arnarthor)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=arnarthor) | [<img src="https://avatars.githubusercontent.com/u/131916?v=3" width="100px;"/><br /><sub>Adam Miskiewicz</sub>](http://www.adammiskiewicz.com/)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=skevy) | [<img src="https://avatars.githubusercontent.com/u/2685242?v=3" width="100px;"/><br /><sub>Ori Livni</sub>](http://www.orilivni.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=oriSomething) |
 | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
-| [<img src="https://avatars.githubusercontent.com/u/6182852?v=3" width="100px;"/><br /><sub>Leon Chen</sub>](https://transcranial.github.io)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=transcranial) | [<img src="https://avatars.githubusercontent.com/u/197597?v=3" width="100px;"/><br /><sub>Christopher Chedeau</sub>](http://blog.vjeux.com/)<br />💬 [💻](https://github.com/prettier/prettier-atom/commits?author=vjeux) 🔌 | [<img src="https://avatars.githubusercontent.com/u/646693?v=3" width="100px;"/><br /><sub>Christoph Geschwind</sub>](http://christoph-geschwind.de)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=1st8) | [<img src="https://avatars.githubusercontent.com/u/35026?v=3" width="100px;"/><br /><sub>Andrew Hutchings</sub>](https://andrewhutchings.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=ahutchings) | [<img src="https://avatars.githubusercontent.com/u/875591?v=3" width="100px;"/><br /><sub>David Schnurr</sub>](http://davidschnurr.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=schnerd) | [<img src="https://avatars.githubusercontent.com/u/484801?v=3" width="100px;"/><br /><sub>Ryan Cole</sub>](http://rycole.com/)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=ryancole) | [<img src="https://avatars0.githubusercontent.com/u/11488612?v=3" width="100px;"/><br /><sub>Dara Hak</sub>](https://github.com/darahak)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=darahak) |
+| [<img src="https://avatars.githubusercontent.com/u/6182852?v=3" width="100px;"/><br /><sub>Leon Chen</sub>](https://transcranial.github.io)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=transcranial) | [<img src="https://avatars.githubusercontent.com/u/197597?v=3" width="100px;"/><br /><sub>Christopher Chedeau</sub>](http://blog.vjeux.com/)<br />💬 [💻](https://github.com/prettier/prettier-atom/commits?author=vjeux) 🔌 | [<img src="https://avatars.githubusercontent.com/u/646693?v=3" width="100px;"/><br /><sub>Christoph Geschwind</sub>](http://christoph-geschwind.de)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=1st8) | [<img src="https://avatars.githubusercontent.com/u/35026?v=3" width="100px;"/><br /><sub>Andrew Hutchings</sub>](https://andrewhutchings.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=ahutchings) | [<img src="https://avatars.githubusercontent.com/u/875591?v=3" width="100px;"/><br /><sub>David Schnurr</sub>](http://davidschnurr.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=schnerd) | [<img src="https://avatars.githubusercontent.com/u/484801?v=3" width="100px;"/><br /><sub>Ryan Cole</sub>](http://rycole.com/)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=ryancole) | [<img src="https://avatars0.githubusercontent.com/u/11488612?v=3" width="100px;"/><br /><sub>Dara Hak</sub>](https://github.com/darahak)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=darahak) [📖](https://github.com/prettier/prettier-atom/commits?author=darahak) |
 | [<img src="https://avatars3.githubusercontent.com/u/487068?v=3" width="100px;"/><br /><sub>Stephen John Sorensen</sub>](http://www.stephenjohnsorensen.com/)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=spudly) | [<img src="https://avatars2.githubusercontent.com/u/13285808?v=3" width="100px;"/><br /><sub>Lukas Geiger</sub>](https://github.com/lgeiger)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=lgeiger) [⚠️](https://github.com/prettier/prettier-atom/commits?author=lgeiger) | [<img src="https://avatars2.githubusercontent.com/u/1517854?v=3" width="100px;"/><br /><sub>Viktor Charypar</sub>](https://github.com/charypar)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=charypar) [⚠️](https://github.com/prettier/prettier-atom/commits?author=charypar) | [<img src="https://avatars0.githubusercontent.com/u/1007436?v=3" width="100px;"/><br /><sub>Mats Högberg</sub>](http://mats.hgbrg.se)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=mhgbrg) |
 <!-- ALL-CONTRIBUTORS-LIST:END -->
 
diff --git a/decls/index.js b/decls/index.js
index f160c62..2e0c00d 100644
--- a/decls/index.js
+++ b/decls/index.js
@@ -50,4 +50,5 @@ declare var atom: {
     getView: (Atom$Workspace) => Atom$View,
   },
   workspace: Atom$Workspace,
+  getVersion: () => string,
 };
diff --git a/dist/displayDebugInfo.js b/dist/displayDebugInfo.js
new file mode 100644
index 0000000..95bc05d
--- /dev/null
+++ b/dist/displayDebugInfo.js
@@ -0,0 +1,15 @@
+'use strict';
+
+var _require = require('./helpers'),
+    getDebugInfo = _require.getDebugInfo;
+
+var displayDebugInfo = function displayDebugInfo() {
+  var info = getDebugInfo();
+  var details = ['Atom version: ' + info.atomVersion, 'prettier-atom version: ' + info.prettierAtomVersion, 'prettier version: ' + info.prettierVersion, 'prettier-eslint version: ' + info.prettierESLintVersion, 'prettier-atom configuration: ' + JSON.stringify(info.prettierAtomConfig, null, 2)].join('\n');
+  atom.notifications.addInfo('prettier-atom: details on current install', {
+    detail: details,
+    dismissable: true
+  });
+};
+
+module.exports = displayDebugInfo;
\ No newline at end of file
diff --git a/dist/executePrettier.js b/dist/executePrettier.js
index de687b5..7191141 100644
--- a/dist/executePrettier.js
+++ b/dist/executePrettier.js
@@ -66,13 +66,17 @@ var executePrettierOnBufferRange = function executePrettierOnBufferRange(editor,
 
 var executePrettierOnEmbeddedScripts = function executePrettierOnEmbeddedScripts(editor) {
   return editor.backwardsScanInBufferRange(EMBEDDED_JS_REGEX, editor.getBuffer().getRange(), function (iter) {
-    // Create new range with start row advanced by 1,
-    // since we cannot use look-behind on variable-length starting
-    // <script ...> tag
     var _iter$range = iter.range,
         start = _iter$range.start,
         end = _iter$range.end;
 
+    // Skip formatting when <script> and </script> on the same line
+
+    if (start.row === end.row) return;
+
+    // Create new range with start row advanced by 1,
+    // since we cannot use look-behind on variable-length starting
+    // <script ...> tag
     var startModified = [start.row + 1, start.column];
     var bufferRange = new iter.range.constructor(startModified, end);
 
diff --git a/dist/helpers.js b/dist/helpers.js
index 6d40008..864f6b8 100644
--- a/dist/helpers.js
+++ b/dist/helpers.js
@@ -7,6 +7,7 @@ var fs = require('fs');
 var minimatch = require('minimatch');
 var path = require('path');
 var bundledPrettier = require('prettier');
+var readPkg = require('read-pkg');
 
 // constants
 var LINE_SEPERATOR_REGEX = /(\r|\n|\r\n)/;
@@ -98,6 +99,10 @@ var isLinterLintCommandDefined = function isLinterLintCommandDefined(editor) {
   });
 };
 
+var getDepPath = function getDepPath(dep) {
+  return path.join(__dirname, '../node_modules', dep);
+};
+
 // public helpers
 var getConfigOption = function getConfigOption(key) {
   return atom.config.get('prettier-atom.' + key);
@@ -187,6 +192,16 @@ var runLinter = function runLinter(editor) {
   return isLinterLintCommandDefined(editor) ? atom.commands.dispatch(atom.views.getView(editor), LINTER_LINT_COMMAND) : undefined;
 };
 
+var getDebugInfo = function getDebugInfo() {
+  return {
+    atomVersion: atom.getVersion(),
+    prettierAtomVersion: readPkg.sync().version,
+    prettierVersion: readPkg.sync(getDepPath('prettier')).version,
+    prettierESLintVersion: readPkg.sync(getDepPath('prettier-eslint')).version,
+    prettierAtomConfig: atom.config.get('prettier-atom')
+  };
+};
+
 module.exports = {
   getConfigOption: getConfigOption,
   shouldDisplayErrors: shouldDisplayErrors,
@@ -206,5 +221,6 @@ module.exports = {
   shouldRespectEslintignore: shouldRespectEslintignore,
   getPrettierOptions: getPrettierOptions,
   getPrettierEslintOptions: getPrettierEslintOptions,
-  runLinter: runLinter
+  runLinter: runLinter,
+  getDebugInfo: getDebugInfo
 };
\ No newline at end of file
diff --git a/dist/main.js b/dist/main.js
index 0c76bc7..74f3f3d 100644
--- a/dist/main.js
+++ b/dist/main.js
@@ -12,6 +12,7 @@ var _require = require('atom'),
 var format = null;
 var formatOnSave = null;
 var warnAboutLinterEslintFixOnSave = null;
+var displayDebugInfo = null;
 var subscriptions = null;
 
 // HACK: lazy load most of the code we need for performance
@@ -39,11 +40,21 @@ var lazyWarnAboutLinterEslintFixOnSave = function lazyWarnAboutLinterEslintFixOn
   warnAboutLinterEslintFixOnSave();
 };
 
+// HACK: lazy load most of the code we need for performance
+var lazyDisplayDebugInfo = function lazyDisplayDebugInfo() {
+  if (!displayDebugInfo) {
+    // eslint-disable-next-line global-require
+    displayDebugInfo = require('./displayDebugInfo');
+  }
+  displayDebugInfo();
+};
+
 // public API
 var activate = function activate() {
   subscriptions = new CompositeDisposable();
 
   subscriptions.add(atom.commands.add('atom-workspace', 'prettier:format', lazyFormat));
+  subscriptions.add(atom.commands.add('atom-workspace', 'prettier:debug', lazyDisplayDebugInfo));
   subscriptions.add(atom.workspace.observeTextEditors(function (editor) {
     return subscriptions.add(editor.getBuffer().onWillSave(function () {
       return lazyFormatOnSave(editor);
diff --git a/menus/prettier-js.json b/menus/prettier-js.json
index bbcb4d0..b7eb6cb 100644
--- a/menus/prettier-js.json
+++ b/menus/prettier-js.json
@@ -17,6 +17,10 @@
             {
               "label": "Format",
               "command": "prettier:format"
+            },
+            {
+              "label": "Debug",
+              "command": "prettier:debug"
             }
           ]
         }
diff --git a/package.json b/package.json
index 86380c0..4946206 100644
--- a/package.json
+++ b/package.json
@@ -25,7 +25,8 @@
     "loophole": "^1.1.0",
     "minimatch": "^3.0.3",
     "prettier": "^1.0.2",
-    "prettier-eslint": "^5.1.0"
+    "prettier-eslint": "^5.1.0",
+    "read-pkg": "^2.0.0"
   },
   "devDependencies": {
     "all-contributors-cli": "^4.1.0",
diff --git a/src/displayDebugInfo.js b/src/displayDebugInfo.js
new file mode 100644
index 0000000..24ca7fb
--- /dev/null
+++ b/src/displayDebugInfo.js
@@ -0,0 +1,18 @@
+const { getDebugInfo } = require('./helpers');
+
+const displayDebugInfo = () => {
+  const info = getDebugInfo();
+  const details = [
+    `Atom version: ${info.atomVersion}`,
+    `prettier-atom version: ${info.prettierAtomVersion}`,
+    `prettier version: ${info.prettierVersion}`,
+    `prettier-eslint version: ${info.prettierESLintVersion}`,
+    `prettier-atom configuration: ${JSON.stringify(info.prettierAtomConfig, null, 2)}`,
+  ].join('\n');
+  atom.notifications.addInfo('prettier-atom: details on current install', {
+    detail: details,
+    dismissable: true,
+  });
+};
+
+module.exports = displayDebugInfo;
diff --git a/src/helpers.js b/src/helpers.js
index 21c1030..bf21cab 100644
--- a/src/helpers.js
+++ b/src/helpers.js
@@ -4,6 +4,7 @@ const fs = require('fs');
 const minimatch = require('minimatch');
 const path = require('path');
 const bundledPrettier = require('prettier');
+const readPkg = require('read-pkg');
 
 // constants
 const LINE_SEPERATOR_REGEX = /(\r|\n|\r\n)/;
@@ -77,6 +78,8 @@ const isLinterLintCommandDefined = (editor: TextEditor) =>
     .findCommands({ target: atom.views.getView(editor) })
     .some(command => command.name === LINTER_LINT_COMMAND);
 
+const getDepPath = (dep: string) => path.join(__dirname, '../node_modules', dep);
+
 // public helpers
 const getConfigOption = (key: string) => atom.config.get(`prettier-atom.${key}`);
 
@@ -141,6 +144,14 @@ const runLinter = (editor: TextEditor) =>
     ? atom.commands.dispatch(atom.views.getView(editor), LINTER_LINT_COMMAND)
     : undefined);
 
+const getDebugInfo = () => ({
+  atomVersion: atom.getVersion(),
+  prettierAtomVersion: readPkg.sync().version,
+  prettierVersion: readPkg.sync(getDepPath('prettier')).version,
+  prettierESLintVersion: readPkg.sync(getDepPath('prettier-eslint')).version,
+  prettierAtomConfig: atom.config.get('prettier-atom'),
+});
+
 module.exports = {
   getConfigOption,
   shouldDisplayErrors,
@@ -161,4 +172,5 @@ module.exports = {
   getPrettierOptions,
   getPrettierEslintOptions,
   runLinter,
+  getDebugInfo,
 };
diff --git a/src/main.js b/src/main.js
index adff6e5..5c91ae7 100644
--- a/src/main.js
+++ b/src/main.js
@@ -6,6 +6,7 @@ const { CompositeDisposable } = require('atom');
 let format = null;
 let formatOnSave = null;
 let warnAboutLinterEslintFixOnSave = null;
+let displayDebugInfo = null;
 let subscriptions = null;
 
 // HACK: lazy load most of the code we need for performance
@@ -33,11 +34,21 @@ const lazyWarnAboutLinterEslintFixOnSave = () => {
   warnAboutLinterEslintFixOnSave();
 };
 
+// HACK: lazy load most of the code we need for performance
+const lazyDisplayDebugInfo = () => {
+  if (!displayDebugInfo) {
+    // eslint-disable-next-line global-require
+    displayDebugInfo = require('./displayDebugInfo');
+  }
+  displayDebugInfo();
+};
+
 // public API
 const activate = () => {
   subscriptions = new CompositeDisposable();
 
   subscriptions.add(atom.commands.add('atom-workspace', 'prettier:format', lazyFormat));
+  subscriptions.add(atom.commands.add('atom-workspace', 'prettier:debug', lazyDisplayDebugInfo));
   subscriptions.add(
     atom.workspace.observeTextEditors(editor =>
       subscriptions.add(editor.getBuffer().onWillSave(() => lazyFormatOnSave(editor))),
diff --git a/yarn.lock b/yarn.lock
index f0b1879..ebca8d8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2738,6 +2738,15 @@ load-json-file@^1.0.0:
     pinkie-promise "^2.0.0"
     strip-bom "^2.0.0"
 
+load-json-file@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
+  dependencies:
+    graceful-fs "^4.1.2"
+    parse-json "^2.2.0"
+    pify "^2.0.0"
+    strip-bom "^3.0.0"
+
 locate-path@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
@@ -3189,6 +3198,12 @@ path-type@^1.0.0:
     pify "^2.0.0"
     pinkie-promise "^2.0.0"
 
+path-type@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
+  dependencies:
+    pify "^2.0.0"
+
 pause-stream@0.0.11:
   version "0.0.11"
   resolved "https://registry.yarnpkg.com/pause-stream/-/pause-stream-0.0.11.tgz#fe5a34b0cbce12b5aa6a2b403ee2e73b602f1445"
@@ -3385,6 +3400,14 @@ read-pkg@^1.0.0:
     normalize-package-data "^2.3.2"
     path-type "^1.0.0"
 
+read-pkg@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
+  dependencies:
+    load-json-file "^2.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^2.0.0"
+
 "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.2, readable-stream@^2.2.2:
   version "2.2.3"
   resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.3.tgz#9cf49463985df016c8ae8813097a9293a9b33729"


Test patch:
diff --git a/src/displayDebugInfo.test.js b/src/displayDebugInfo.test.js
new file mode 100644
index 0000000..07656b2
--- /dev/null
+++ b/src/displayDebugInfo.test.js
@@ -0,0 +1,30 @@
+// @flow
+const displayDebugInfo = require('./displayDebugInfo');
+
+test('it displays a notification on Atom with package information', () => {
+  let title;
+  let options;
+
+  atom = {
+    getVersion: jest.fn(),
+    config: {
+      get: jest.fn(),
+    },
+    notifications: {
+      addInfo: jest.fn((msg, opts) => {
+        title = msg;
+        options = opts;
+      }),
+    },
+  };
+
+  displayDebugInfo();
+  expect(atom.notifications.addInfo).toHaveBeenCalled();
+  expect(title).toContain('prettier-atom');
+  // $FlowFixMe
+  expect(typeof options.detail).toBe('string');
+  // $FlowFixMe
+  expect(options.detail.length).toBeGreaterThan(0);
+  // $FlowFixMe
+  expect(options.dismissable).toBe(true);
+});
diff --git a/src/helpers.test.js b/src/helpers.test.js
index 14a6072..15edb85 100644
--- a/src/helpers.test.js
+++ b/src/helpers.test.js
@@ -22,6 +22,7 @@ const {
   getPrettierOptions,
   getPrettierEslintOptions,
   runLinter,
+  getDebugInfo,
 } = require('./helpers');
 
 jest.mock('atom-linter');
@@ -405,3 +406,28 @@ describe('runLinter()', () => {
     expect(atom.commands.dispatch).not.toHaveBeenCalled();
   });
 });
+
+describe('getDebugInfo()', () => {
+  test('returns versions of prettier-atom + dependencies, and its configuration', () => {
+    const expectedAtomVersion = '4.44.44';
+    const expectedConfig = 'config';
+    const mockGetVersion = jest.fn(() => expectedAtomVersion);
+    const mockGet = jest.fn(() => expectedConfig);
+    atom = {
+      getVersion: mockGetVersion,
+      config: { get: mockGet },
+    };
+
+    const minVersionLength = '0.0.0'.length;
+    const info = getDebugInfo();
+
+    expect(info.atomVersion).toBe(expectedAtomVersion);
+    expect(typeof info.prettierVersion).toBe('string');
+    expect(typeof info.prettierAtomVersion).toBe('string');
+    expect(typeof info.prettierESLintVersion).toBe('string');
+    expect(info.prettierVersion.length).toBeGreaterThanOrEqual(minVersionLength);
+    expect(info.prettierAtomVersion.length).toBeGreaterThanOrEqual(minVersionLength);
+    expect(info.prettierESLintVersion.length).toBeGreaterThanOrEqual(minVersionLength);
+    expect(info.prettierAtomConfig).toBe(expectedConfig);
+  });
+});