Repository: prettier/prettier-atom
Pull request #495 (2019-04-15 05:31:39)

feat: Add option to enable format-on-save for files in node_modules
Currently it seems to be impossible to configure prettier-atom to 
format-on-save for files in node_modules, even by explicitly adding 
node_modules to the whitelist glob. This seems to be due to the fact 
that isFileFormattable defers to prettier's getFileInfo function, which 
by default will return `ignored: true` for files in node_modules, unless 
withNodeModules is passed in as an option. 

This PR introduces the ability to configure this behavior using a new 
ignoreNodeModules option. Suggestions on naming/copy for the option flag 
name/descriptions are very welcome, as are any suggestions people might 
have for testing/implementation.

I've defaulted the option to true for now to preserve existing behavior, 
though we may want to consider changing this default in a major version, 
because the current default can be a bit non-intuitive because users 
have plenty of other ways to explicitly exclude files from 
formatting-on-save (.prettierignore, exclusion glob, toggling 
format-on-save on/off, etc), so adding another layer of opaque default 
exclusions on top of that can make it seem like format-on-save is 
getting disabled arbitrarily on certain files (at least that was my 
impression at first until I looked deeper). FWIW the prettier extension 
for VSCode does format-on-save files in node_modules by default, and 
people don't seem to have any issues with it (presumably because those 
who care can simply configure it as a default exclusion).


Patch:
diff --git a/.all-contributorsrc b/.all-contributorsrc
index 6755548..bd170e9 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -303,6 +303,16 @@
         "code",
         "design"
       ]
+    },
+    {
+      "login": "lewisl9029",
+      "name": "Lewis Liu",
+      "avatar_url": "https://avatars0.githubusercontent.com/u/6934200?v=4",
+      "profile": "https://github.com/lewisl9029",
+      "contributions": [
+        "code",
+        "test"
+      ]
     }
   ],
   "repoType": "github"
diff --git a/README.md b/README.md
index 97a6424..bb98536 100644
--- a/README.md
+++ b/README.md
@@ -109,8 +109,7 @@ Thanks goes to these people ([emoji key][emojis]):
 | [<img src="https://avatars.githubusercontent.com/u/6182852?v=3" width="100px;"/><br /><sub><b>Leon Chen</b></sub>](https://transcranial.github.io)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=transcranial "Code") | [<img src="https://avatars.githubusercontent.com/u/197597?v=3" width="100px;"/><br /><sub><b>Christopher Chedeau</b></sub>](http://blog.vjeux.com/)<br />[💬](#question-vjeux "Answering Questions") [💻](https://github.com/prettier/prettier-atom/commits?author=vjeux "Code") [🔌](#plugin-vjeux "Plugin/utility libraries") | [<img src="https://avatars.githubusercontent.com/u/646693?v=3" width="100px;"/><br /><sub><b>Christoph Geschwind</b></sub>](http://christoph-geschwind.de)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=1st8 "Code") | [<img src="https://avatars.githubusercontent.com/u/35026?v=3" width="100px;"/><br /><sub><b>Andrew Hutchings</b></sub>](https://andrewhutchings.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=ahutchings "Code") | [<img src="https://avatars.githubusercontent.com/u/875591?v=3" width="100px;"/><br /><sub><b>David Schnurr</b></sub>](http://davidschnurr.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=schnerd "Code") | [<img src="https://avatars.githubusercontent.com/u/484801?v=3" width="100px;"/><br /><sub><b>Ryan Cole</b></sub>](http://rycole.com/)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=ryancole "Code") | [<img src="https://avatars0.githubusercontent.com/u/11488612?v=3" width="100px;"/><br /><sub><b>Dara Hak</b></sub>](https://github.com/darahak)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=darahak "Code") [📖](https://github.com/prettier/prettier-atom/commits?author=darahak "Documentation") |
 | [<img src="https://avatars3.githubusercontent.com/u/487068?v=3" width="100px;"/><br /><sub><b>Stephen John Sorensen</b></sub>](http://www.stephenjohnsorensen.com/)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=spudly "Code") | [<img src="https://avatars2.githubusercontent.com/u/13285808?v=3" width="100px;"/><br /><sub><b>Lukas Geiger</b></sub>](https://github.com/lgeiger)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=lgeiger "Code") [⚠️](https://github.com/prettier/prettier-atom/commits?author=lgeiger "Tests") | [<img src="https://avatars2.githubusercontent.com/u/1517854?v=3" width="100px;"/><br /><sub><b>Viktor Charypar</b></sub>](https://github.com/charypar)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=charypar "Code") [⚠️](https://github.com/prettier/prettier-atom/commits?author=charypar "Tests") | [<img src="https://avatars0.githubusercontent.com/u/1007436?v=3" width="100px;"/><br /><sub><b>Mats Högberg</b></sub>](http://mats.hgbrg.se)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=mhgbrg "Code") | [<img src="https://avatars0.githubusercontent.com/u/2602767?v=3" width="100px;"/><br /><sub><b>Roman</b></sub>](https://github.com/RoM4iK)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=RoM4iK "Code") | [<img src="https://avatars2.githubusercontent.com/u/1468518?v=3" width="100px;"/><br /><sub><b>vaibhav</b></sub>](https://vaibhavchatarkar.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=da-vaibhav "Code") | [<img src="https://avatars1.githubusercontent.com/u/1935696?v=3" width="100px;"/><br /><sub><b>Karl Horky</b></sub>](https://work.karlhorky.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=karlhorky "Code") |
 | [<img src="https://avatars3.githubusercontent.com/u/810438?v=3" width="100px;"/><br /><sub><b>Dan Abramov</b></sub>](http://twitter.com/dan_abramov)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=gaearon "Code") | [<img src="https://avatars3.githubusercontent.com/u/1227109?v=3" width="100px;"/><br /><sub><b>Murphy Randle</b></sub>](https://sploding.rocks)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=splodingsocks "Code") [🐛](https://github.com/prettier/prettier-atom/issues?q=author%3Asplodingsocks "Bug reports") | [<img src="https://avatars3.githubusercontent.com/u/8517072?v=3" width="100px;"/><br /><sub><b>Matthieu Lemoine</b></sub>](https://matthieulemoine.com)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=MatthieuLemoine "Code") | [<img src="https://avatars1.githubusercontent.com/u/37242?v=4" width="100px;"/><br /><sub><b>Ron Green</b></sub>](https://github.com/rgreenjr)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=rgreenjr "Code") | [<img src="https://avatars2.githubusercontent.com/u/1745854?v=4" width="100px;"/><br /><sub><b>Harold Treen</b></sub>](https://haroldtreen.com)<br />[🐛](https://github.com/prettier/prettier-atom/issues?q=author%3Aharoldtreen "Bug reports") [💻](https://github.com/prettier/prettier-atom/commits?author=haroldtreen "Code") | [<img src="https://avatars1.githubusercontent.com/u/3447641?v=4" width="100px;"/><br /><sub><b>Nikita Mashukov</b></sub>](https://github.com/ferdibiflator)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=ferdibiflator "Code") | [<img src="https://avatars0.githubusercontent.com/u/8203211?v=4" width="100px;"/><br /><sub><b>Sam Horton</b></sub>](https://github.com/SavePointSam)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=SavePointSam "Code") [⚠️](https://github.com/prettier/prettier-atom/commits?author=SavePointSam "Tests") |
-| [<img src="https://avatars2.githubusercontent.com/u/5957709?v=4" width="100px;"/><br /><sub><b>olsonpm</b></sub>](https://github.com/olsonpm)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=olsonpm "Code") | [<img src="https://avatars2.githubusercontent.com/u/63201?v=4" width="100px;"/><br /><sub><b>David Singleton</b></sub>](http://dsingleton.co.uk)<br />[📖](https://github.com/prettier/prettier-atom/commits?author=dsingleton "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/4378?v=4" width="100px;"/><br /><sub><b>Chris Drackett</b></sub>](https://github.com/chrisdrackett)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=chrisdrackett "Code") [🎨](#design-chrisdrackett "Design") |
-
+| [<img src="https://avatars2.githubusercontent.com/u/5957709?v=4" width="100px;"/><br /><sub><b>olsonpm</b></sub>](https://github.com/olsonpm)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=olsonpm "Code") | [<img src="https://avatars2.githubusercontent.com/u/63201?v=4" width="100px;"/><br /><sub><b>David Singleton</b></sub>](http://dsingleton.co.uk)<br />[📖](https://github.com/prettier/prettier-atom/commits?author=dsingleton "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/4378?v=4" width="100px;"/><br /><sub><b>Chris Drackett</b></sub>](https://github.com/chrisdrackett)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=chrisdrackett "Code") [🎨](#design-chrisdrackett "Design") | [<img src="https://avatars0.githubusercontent.com/u/6934200?v=4" width="100px;"/><br /><sub><b>Lewis Liu</b></sub>](https://github.com/lewisl9029)<br />[💻](https://github.com/prettier/prettier-atom/commits?author=lewisl9029 "Code") [⚠️](https://github.com/prettier/prettier-atom/commits?author=lewisl9029 "Tests") |
 <!-- ALL-CONTRIBUTORS-LIST:END -->
 
 This project follows the [all-contributors][all-contributors] specification. Contributions of any kind are welcome!
diff --git a/dist/atomInterface/index.js b/dist/atomInterface/index.js
index c04f02d..751d5f2 100644
--- a/dist/atomInterface/index.js
+++ b/dist/atomInterface/index.js
@@ -34,6 +34,8 @@ const isDisabledIfNoConfigFile = () => getConfigOption('formatOnSaveOptions.isDi
 
 const shouldRespectEslintignore = () => getConfigOption('formatOnSaveOptions.respectEslintignore');
 
+const shouldIgnoreNodeModules = () => getConfigOption('formatOnSaveOptions.ignoreNodeModules');
+
 const toggleFormatOnSave = () => setConfigOption('formatOnSaveOptions.enabled', !isFormatOnSaveEnabled());
 
 const getPrettierEslintOptions = () => getConfigOption('prettierEslintOptions');
@@ -94,6 +96,7 @@ module.exports = {
   isLinterEslintAutofixEnabled,
   relativizePathFromAtomProject,
   runLinter,
+  shouldIgnoreNodeModules,
   shouldRespectEslintignore,
   shouldUseEslint,
   shouldUseStylelint,
diff --git a/dist/config-schema.json b/dist/config-schema.json
index 5f3998c..e74341a 100644
--- a/dist/config-schema.json
+++ b/dist/config-schema.json
@@ -72,6 +72,13 @@
         "type": "boolean",
         "default": false,
         "order": 7
+      },
+      "ignoreNodeModules": {
+        "title": "Ignore Files in `node_modules`",
+        "description": "Ignores Files in `node_modules` from format on save.",
+        "type": "boolean",
+        "default": true,
+        "order": 8
       }
     }
   },
diff --git a/dist/helpers/isFileFormattable.js b/dist/helpers/isFileFormattable.js
index fe93f4c..c88f93f 100644
--- a/dist/helpers/isFileFormattable.js
+++ b/dist/helpers/isFileFormattable.js
@@ -2,6 +2,7 @@
 
 const _ = require('lodash/fp');
 const getPrettierInstance = require('./getPrettierInstance');
+const { shouldIgnoreNodeModules } = require('../atomInterface');
 const { getCurrentFilePath, isCurrentFilePathDefined } = require('../editorInterface');
 const { findCachedFromFilePath } = require('./general');
 
@@ -10,6 +11,7 @@ const getNearestPrettierignorePath = filePath => findCachedFromFilePath(filePath
 const getPrettierFileInfoForCurrentFilePath = (editor
 // $FlowFixMe: getFileInfo.sync needs to be addded to flow-typed
 ) => getPrettierInstance(editor).getFileInfo.sync(getCurrentFilePath(editor), {
+  withNodeModules: !shouldIgnoreNodeModules(),
   // $FlowIssue: we know filepath is defined at this point
   ignorePath: getNearestPrettierignorePath(getCurrentFilePath(editor))
 });
diff --git a/src/atomInterface/index.js b/src/atomInterface/index.js
index 2dff6e9..3eafa55 100644
--- a/src/atomInterface/index.js
+++ b/src/atomInterface/index.js
@@ -32,6 +32,8 @@ const isDisabledIfNoConfigFile = () => getConfigOption('formatOnSaveOptions.isDi
 
 const shouldRespectEslintignore = () => getConfigOption('formatOnSaveOptions.respectEslintignore');
 
+const shouldIgnoreNodeModules = () => getConfigOption('formatOnSaveOptions.ignoreNodeModules');
+
 const toggleFormatOnSave = () => setConfigOption('formatOnSaveOptions.enabled', !isFormatOnSaveEnabled());
 
 const getPrettierEslintOptions = () => getConfigOption('prettierEslintOptions');
@@ -104,6 +106,7 @@ module.exports = {
   isLinterEslintAutofixEnabled,
   relativizePathFromAtomProject,
   runLinter,
+  shouldIgnoreNodeModules,
   shouldRespectEslintignore,
   shouldUseEslint,
   shouldUseStylelint,
diff --git a/src/config-schema.json b/src/config-schema.json
index 5f3998c..e74341a 100644
--- a/src/config-schema.json
+++ b/src/config-schema.json
@@ -72,6 +72,13 @@
         "type": "boolean",
         "default": false,
         "order": 7
+      },
+      "ignoreNodeModules": {
+        "title": "Ignore Files in `node_modules`",
+        "description": "Ignores Files in `node_modules` from format on save.",
+        "type": "boolean",
+        "default": true,
+        "order": 8
       }
     }
   },
diff --git a/src/helpers/isFileFormattable.js b/src/helpers/isFileFormattable.js
index b558e28..7c490ed 100644
--- a/src/helpers/isFileFormattable.js
+++ b/src/helpers/isFileFormattable.js
@@ -1,6 +1,7 @@
 // @flow
 const _ = require('lodash/fp');
 const getPrettierInstance = require('./getPrettierInstance');
+const { shouldIgnoreNodeModules } = require('../atomInterface');
 const { getCurrentFilePath, isCurrentFilePathDefined } = require('../editorInterface');
 const { findCachedFromFilePath } = require('./general');
 
@@ -10,6 +11,7 @@ const getNearestPrettierignorePath = (filePath: FilePath): ?FilePath =>
 const getPrettierFileInfoForCurrentFilePath = (editor: TextEditor): Prettier$FileInfo =>
   // $FlowFixMe: getFileInfo.sync needs to be addded to flow-typed
   getPrettierInstance(editor).getFileInfo.sync(getCurrentFilePath(editor), {
+    withNodeModules: !shouldIgnoreNodeModules(),
     // $FlowIssue: we know filepath is defined at this point
     ignorePath: getNearestPrettierignorePath(getCurrentFilePath(editor)),
   });


Test patch:
diff --git a/src/helpers/isFileFormattable.test.js b/src/helpers/isFileFormattable.test.js
index 3ab88ed..9e08ca8 100644
--- a/src/helpers/isFileFormattable.test.js
+++ b/src/helpers/isFileFormattable.test.js
@@ -1,16 +1,19 @@
 jest.mock('./getPrettierInstance');
+jest.mock('../atomInterface');
 jest.mock('../editorInterface');
 jest.mock('./general');
 
 const isFileFormattable = require('./isFileFormattable');
 const buildMockEditor = require('../../tests/mocks/textEditor');
 const getPrettierInstance = require('./getPrettierInstance');
+const { shouldIgnoreNodeModules } = require('../atomInterface');
 const { getCurrentFilePath, isCurrentFilePathDefined } = require('../editorInterface');
 const { findCachedFromFilePath } = require('./general');
 
 const mockEditor = buildMockEditor();
 
 beforeEach(() => {
+  shouldIgnoreNodeModules.mockImplementation(() => true);
   isCurrentFilePathDefined.mockImplementation(() => true);
   getCurrentFilePath.mockImplementation(() => 'xyz.js');
   findCachedFromFilePath.mockImplementation(() => '.prettierignore');
@@ -22,11 +25,12 @@ const mockGetFileInfoSyncFunc = syncFunc =>
 it('calls prettier.getFileInfo.sync with the proper arguments', () => {
   const sync = jest.fn();
   mockGetFileInfoSyncFunc(sync);
+  shouldIgnoreNodeModules.mockImplementation(() => false);
   getPrettierInstance.mockImplementation(() => ({ getFileInfo: { sync } }));
 
   isFileFormattable(mockEditor);
 
-  expect(sync).toHaveBeenCalledWith('xyz.js', { ignorePath: '.prettierignore' });
+  expect(sync).toHaveBeenCalledWith('xyz.js', { withNodeModules: true, ignorePath: '.prettierignore' });
 });
 
 it('returns true if the file is formattable', () => {