Repository: prettier/prettier-atom
Pull request #261 (2017-09-04 03:25:58)

Implement Prettier Config

MrLoh: can't wait for this, thanks a lot for the hard work
darahak: We should consider commiting transpiled files separately. It's a bit difficult to navigate and review big changes.
We can update the contributing guides accordingly.
robwise: @darahak So you think:

 **keep**:
- formatting options 
- editorconfig inference

**remove**:
- blacklist globs
- whitelist globs
- ability to not format on save if prettier is not installed locally
- parser-specific scopes (or maybe we still need this? — will investigate)
darahak: @robwise Yes, basically keep formatting options because they are still a good interface for CLI single options, and EditorConfig support because Prettier Config is not a complete replacement IMO (see https://github.com/prettier/prettier/issues/42 for related discussion).

I'm not sure about these two:

> - ability to not format on save if prettier is not installed locally
> - parser-specific scopes (or maybe we still need this? — will investigate)

In the end, it's just my opinion. It would be great to have some feedback from users.
Maybe do a beta or a pre-release?
darahak: On second thought, would it be a good idea to add an option that says: only use Prettier Config or default options (current proposal)?

If it's disabled, the package is able to fall back on user settings.
darahak: Current PR for EditorConfig support: https://github.com/prettier/prettier/pull/2760
robwise: Just an update, still working on this, but I have to wait until Prettier releases `resolveConfig.sync` as otherwise Atom's save doesn't get blocked and we format too late in some cases (also needs the release from prettier-eslint that reverts back to synchronous as well: https://github.com/prettier/prettier-eslint/pull/123)
codecov-io: # [Codecov](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=h1) Report
> Merging [#261](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=desc) into [master](https://codecov.io/gh/prettier/prettier-atom/commit/cac91ab88c0430056c16853efe984d0567cb0e3e?src=pr&el=desc) will **increase** coverage by `1.06%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/prettier/prettier-atom/pull/261/graphs/tree.svg?height=150&width=650&src=pr&token=Pdibkvk5Zo)](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #261      +/-   ##
==========================================
+ Coverage   76.29%   77.35%   +1.06%     
==========================================
  Files          26       27       +1     
  Lines         426      446      +20     
  Branches       40       42       +2     
==========================================
+ Hits          325      345      +20     
  Misses         87       87              
  Partials       14       14
```


| [Impacted Files](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [src/helpers/getPrettierInstance.js](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=tree#diff-c3JjL2hlbHBlcnMvZ2V0UHJldHRpZXJJbnN0YW5jZS5qcw==) | `100% <ø> (ø)` | |
| [...rc/executePrettier/executePrettierOnBufferRange.js](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=tree#diff-c3JjL2V4ZWN1dGVQcmV0dGllci9leGVjdXRlUHJldHRpZXJPbkJ1ZmZlclJhbmdlLmpz) | `100% <100%> (ø)` | :arrow_up: |
| [src/executePrettier/buildPrettierOptions.js](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=tree#diff-c3JjL2V4ZWN1dGVQcmV0dGllci9idWlsZFByZXR0aWVyT3B0aW9ucy5qcw==) | `100% <100%> (ø)` | :arrow_up: |
| [src/formatOnSave/isFilePathPrettierIgnored.js](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=tree#diff-c3JjL2Zvcm1hdE9uU2F2ZS9pc0ZpbGVQYXRoUHJldHRpZXJJZ25vcmVkLmpz) | `100% <100%> (ø)` | |
| [src/helpers/index.js](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=tree#diff-c3JjL2hlbHBlcnMvaW5kZXguanM=) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=footer). Last update [cac91ab...1adfed0](https://codecov.io/gh/prettier/prettier-atom/pull/261?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

azz: Tracking for 1.6.2 which will include .sync() https://github.com/prettier/prettier/issues/2804

Patch:
diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..4227ad8
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,3 @@
+dist
+flow-typed
+node_modules
diff --git a/.prettierrc b/.prettierrc
new file mode 100644
index 0000000..e69de29
diff --git a/dist/atomInterface/index.js b/dist/atomInterface/index.js
index 49a2fef..eced01c 100644
--- a/dist/atomInterface/index.js
+++ b/dist/atomInterface/index.js
@@ -41,6 +41,10 @@ var isDisabledIfNotInPackageJson = function isDisabledIfNotInPackageJson() {
   return getConfigOption('formatOnSaveOptions.isDisabledIfNotInPackageJson');
 };
 
+var isDisabledIfNoConfigFile = function isDisabledIfNoConfigFile() {
+  return getConfigOption('formatOnSaveOptions.isDisabledIfNoConfigFile');
+};
+
 var shouldRespectEslintignore = function shouldRespectEslintignore() {
   return getConfigOption('formatOnSaveOptions.respectEslintignore');
 };
@@ -152,6 +156,7 @@ module.exports = {
   getAllScopes: getAllScopes,
   getWhitelistedGlobs: getWhitelistedGlobs,
   isDisabledIfNotInPackageJson: isDisabledIfNotInPackageJson,
+  isDisabledIfNoConfigFile: isDisabledIfNoConfigFile,
   isFormatOnSaveEnabled: isFormatOnSaveEnabled,
   isLinterEslintAutofixEnabled: isLinterEslintAutofixEnabled,
   runLinter: runLinter,
diff --git a/dist/config-schema.json b/dist/config-schema.json
index d6b5c73..e0112da 100644
--- a/dist/config-schema.json
+++ b/dist/config-schema.json
@@ -1,14 +1,16 @@
 {
   "useEslint": {
     "title": "ESLint Integration",
-    "description": "Use [prettier-eslint](https://github.com/prettier/prettier-eslint) to infer your Prettier settings based on your ESLint config. If we cannot infer a Prettier setting from your ESLint config (or if there is none in the current project), we will fallback to using your settings in the *Prettier Options* section.<br><br>**Note:** If you enable *Format on Save*, we recommend disabling ESlint's auto-fix to prevent fixing your code twice.",
+    "description":
+      "Use [prettier-eslint](https://github.com/prettier/prettier-eslint) to infer your Prettier settings based on your ESLint config. If we cannot infer a Prettier setting from your ESLint config (or if there is none in the current project), we will fallback to using your settings in the *Prettier Options* section.<br><br>**Note:** If you enable *Format on Save*, we recommend disabling ESlint's auto-fix to prevent fixing your code twice.",
     "type": "boolean",
     "default": false,
     "order": 1
   },
   "useEditorConfig": {
     "title": "EditorConfig Integration",
-    "description": "Use [EditorConfig](http://editorconfig.org/) configuration to load project-based settings for Prettier formatting.<br>Takes precedence over your settings. The following settings will be overriden if they are found in your `.editorconfig`: **Use tabs**, **Tab width**, **Print width**.",
+    "description":
+      "Use [EditorConfig](http://editorconfig.org/) configuration to load project-based settings for Prettier formatting.<br>Takes precedence over your settings. The following settings will be overriden if they are found in your `.editorconfig`: **Use tabs**, **Tab width**, **Print width**.",
     "type": "boolean",
     "default": true,
     "order": 2
@@ -41,7 +43,8 @@
       },
       "javascriptScopes": {
         "title": "JavaScript Scopes",
-        "description": "Select which files containing JavaScript should be formatted.<br>Use the command `Editor: Log Cursor Scope` to determine the scopes for a file.",
+        "description":
+          "Select which files containing JavaScript should be formatted.<br>Use the command `Editor: Log Cursor Scope` to determine the scopes for a file.",
         "type": "array",
         "default": [
           "source.js",
@@ -59,7 +62,8 @@
       },
       "typescriptScopes": {
         "title": "TypeScript Scopes",
-        "description": "Select which files containing TypeScript should be formatted.<br>Use the command `Editor: Log Cursor Scope` to determine the scopes for a file.",
+        "description":
+          "Select which files containing TypeScript should be formatted.<br>Use the command `Editor: Log Cursor Scope` to determine the scopes for a file.",
         "type": "array",
         "default": ["source.ts", "source.tsx", "source.ts.tsx"],
         "items": {
@@ -69,7 +73,8 @@
       },
       "cssScopes": {
         "title": "CSS Scopes",
-        "description": "Select which files containing CSS should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
+        "description":
+          "Select which files containing CSS should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
         "type": "array",
         "default": ["source.css", "source.less", "source.css.less", "source.scss", "source.css.scss"],
         "items": {
@@ -79,7 +84,8 @@
       },
       "jsonScopes": {
         "title": "JSON Scopes",
-        "description": "Select which files containing JSON should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
+        "description":
+          "Select which files containing JSON should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
         "type": "array",
         "default": ["source.json"],
         "items": {
@@ -89,7 +95,8 @@
       },
       "graphQlScopes": {
         "title": "GraphQL Scopes",
-        "description": "Select which files containing GraphQL should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
+        "description":
+          "Select which files containing GraphQL should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
         "type": "array",
         "default": ["source.graphql"],
         "items": {
@@ -99,24 +106,35 @@
       },
       "excludedGlobs": {
         "title": "Exclude (list of globs)",
-        "description": "A list of file globs to exclude from formatting on save (takes precedence over scopes). Use commas to separate each glob.",
+        "description":
+          "A list of file globs to exclude from formatting on save (takes precedence over scopes). Use commas to separate each glob.",
         "type": "array",
         "default": [],
         "order": 9
       },
       "whitelistedGlobs": {
         "title": "Include (list of globs)",
-        "description": "A list of file globs to always format on save (takes precedence over scopes and excluded globs). Use commas to separate each glob.<br><br>**Note:** If there are globs in this list, files not matching the globs will not be formatted on save, regardless of other options.",
+        "description":
+          "A list of file globs to always format on save (takes precedence over scopes and excluded globs). Use commas to separate each glob.<br><br>**Note:** If there are globs in this list, files not matching the globs will not be formatted on save, regardless of other options.",
         "type": "array",
         "default": [],
         "order": 10
       },
       "isDisabledIfNotInPackageJson": {
         "title": "Only format if Prettier is found in your project's dependencies",
-        "description": "Only format on save when `prettier` (or `prettier-eslint`/`prettier-eslint-cli` if using *ESLint integration*) is in your project's `package.json` (dependencies or devDependencies)",
+        "description":
+          "Only format on save when `prettier` (or `prettier-eslint`/`prettier-eslint-cli` if using *ESLint integration*) is in your project's `package.json` (dependencies or devDependencies)",
         "type": "boolean",
         "default": false,
         "order": 11
+      },
+      "isDisabledIfNoConfigFile": {
+        "title": "Only format if a Prettier config is found",
+        "description":
+          "Only format on save if we find a `.prettierrc` file (written in YAML or JSON), a `prettier.config.js` file that exports an object, or a 'prettier' key in your `package.json` file. <br><br>**Note:** You must have at least one valid rule in order for your config to be considered present.",
+        "type": "boolean",
+        "default": false,
+        "order": 12
       }
     }
   },
@@ -183,7 +201,8 @@
       },
       "parser": {
         "title": "JavaScript Parser",
-        "description": "Choose which [supported parser](https://www.npmjs.com/package/prettier#language-support) to use. (Does not apply to TypeScript, CSS or JSON)",
+        "description":
+          "Choose which [supported parser](https://www.npmjs.com/package/prettier#language-support) to use. (Does not apply to TypeScript, CSS or JSON)",
         "type": "string",
         "default": "babylon",
         "enum": ["babylon", "flow"],
diff --git a/dist/executePrettier/buildPrettierOptions.js b/dist/executePrettier/buildPrettierOptions.js
index ab68df6..9f66a4d 100644
--- a/dist/executePrettier/buildPrettierOptions.js
+++ b/dist/executePrettier/buildPrettierOptions.js
@@ -18,12 +18,19 @@ var _require2 = require('../atomInterface'),
 
 var buildEditorConfigOptions = require('./buildEditorConfigOptions');
 
+var _require3 = require('../helpers'),
+    getPrettierInstance = _require3.getPrettierInstance;
+
 var isDefined = _.negate(_.isNil);
 
 var isAppropriateToBuildEditorConfigOptions = _.overEvery([isDefined, shouldUseEditorConfig]);
 
 var buildEditorConfigOptionsIfAppropriate = _.flow(getCurrentFilePath, _.cond([[isAppropriateToBuildEditorConfigOptions, buildEditorConfigOptions]]));
 
+var getPrettierConfigOptions = _.cond([[_.flow(getCurrentFilePath, isDefined), function (editor) {
+  return isDefined(getPrettierInstance(editor).resolveConfig.sync) ? getPrettierInstance(editor).resolveConfig.sync(getCurrentFilePath(editor)) : null;
+}]]);
+
 var buildPrettierOptions = function buildPrettierOptions(editor) {
   var optionsFromSettings = getPrettierOptions();
 
@@ -48,7 +55,7 @@ var buildPrettierOptions = function buildPrettierOptions(editor) {
     optionsFromSettings.parser = 'graphql';
   }
 
-  return _extends({}, optionsFromSettings, buildEditorConfigOptionsIfAppropriate(editor));
+  return _extends({}, optionsFromSettings, buildEditorConfigOptionsIfAppropriate(editor), getPrettierConfigOptions(editor));
 };
 
 module.exports = buildPrettierOptions;
\ No newline at end of file
diff --git a/dist/executePrettier/executePrettierOnBufferRange.js b/dist/executePrettier/executePrettierOnBufferRange.js
index 6f84170..cb366f6 100644
--- a/dist/executePrettier/executePrettierOnBufferRange.js
+++ b/dist/executePrettier/executePrettierOnBufferRange.js
@@ -10,7 +10,9 @@ var _require2 = require('../atomInterface'),
     shouldUseEslint = _require2.shouldUseEslint,
     runLinter = _require2.runLinter;
 
-var getPrettierInstance = require('./getPrettierInstance');
+var _require3 = require('../helpers'),
+    getPrettierInstance = _require3.getPrettierInstance;
+
 var buildPrettierEslintOptions = require('./buildPrettierEslintOptions');
 var buildPrettierOptions = require('./buildPrettierOptions');
 var handleError = require('./handleError');
diff --git a/dist/formatOnSave/isFilePathPrettierIgnored.js b/dist/formatOnSave/isFilePathPrettierIgnored.js
new file mode 100644
index 0000000..0e09336
--- /dev/null
+++ b/dist/formatOnSave/isFilePathPrettierIgnored.js
@@ -0,0 +1,34 @@
+'use strict';
+
+var _ = require('lodash/fp');
+var path = require('path');
+var fs = require('fs');
+
+var _require = require('../helpers'),
+    findCachedFromFilePath = _require.findCachedFromFilePath,
+    getDirFromFilePath = _require.getDirFromFilePath,
+    someGlobsMatchFilePath = _require.someGlobsMatchFilePath;
+
+var LINE_SEPERATOR_REGEX = /(\r|\n|\r\n)/;
+
+var getNearestPrettierIgnorePath = function getNearestPrettierIgnorePath(filePath) {
+  return findCachedFromFilePath(filePath, '.prettierignore');
+};
+
+var safeRelativePath = _.curry(function (from, to) {
+  return !!from && !!to ? path.relative(from, to) : undefined;
+});
+
+var getFilePathRelativeToPrettierIgnore = function getFilePathRelativeToPrettierIgnore(filePath) {
+  return _.flow(getNearestPrettierIgnorePath, getDirFromFilePath, safeRelativePath(_, filePath))(filePath);
+};
+
+var getLinesFromFilePath = function getLinesFromFilePath(filePath) {
+  return !!filePath && filePath.length > 0 ? fs.readFileSync(filePath, 'utf8').split(LINE_SEPERATOR_REGEX) : [];
+};
+
+var getIgnoredGlobsFromNearestPrettierIgnore = _.flow(getNearestPrettierIgnorePath, getLinesFromFilePath);
+
+var isFilePathPrettierIgnored = _.flow(_.over([getIgnoredGlobsFromNearestPrettierIgnore, getFilePathRelativeToPrettierIgnore]), _.spread(someGlobsMatchFilePath));
+
+module.exports = isFilePathPrettierIgnored;
\ No newline at end of file
diff --git a/dist/formatOnSave/shouldFormatOnSave.js b/dist/formatOnSave/shouldFormatOnSave.js
index 55e2433..d7a0f68 100644
--- a/dist/formatOnSave/shouldFormatOnSave.js
+++ b/dist/formatOnSave/shouldFormatOnSave.js
@@ -3,7 +3,8 @@
 var _ = require('lodash/fp');
 
 var _require = require('../helpers'),
-    someGlobsMatchFilePath = _require.someGlobsMatchFilePath;
+    someGlobsMatchFilePath = _require.someGlobsMatchFilePath,
+    getPrettierInstance = _require.getPrettierInstance;
 
 var _require2 = require('../editorInterface'),
     getCurrentFilePath = _require2.getCurrentFilePath,
@@ -14,9 +15,11 @@ var _require3 = require('../atomInterface'),
     getAllScopes = _require3.getAllScopes,
     getExcludedGlobs = _require3.getExcludedGlobs,
     getWhitelistedGlobs = _require3.getWhitelistedGlobs,
-    isDisabledIfNotInPackageJson = _require3.isDisabledIfNotInPackageJson;
+    isDisabledIfNotInPackageJson = _require3.isDisabledIfNotInPackageJson,
+    isDisabledIfNoConfigFile = _require3.isDisabledIfNoConfigFile;
 
 var isFilePathEslintignored = require('./isFilePathEslintIgnored');
+var isFilePathPrettierIgnored = require('./isFilePathPrettierIgnored');
 var isPrettierInPackageJson = require('./isPrettierInPackageJson');
 
 var hasFilePath = function hasFilePath(editor) {
@@ -39,6 +42,12 @@ var isFilePathWhitelisted = _.flow(getCurrentFilePath, function (filePath) {
 
 var isFilePathNotEslintignored = _.flow(getCurrentFilePath, _.negate(isFilePathEslintignored));
 
-var shouldFormatOnSave = _.overEvery([isFormatOnSaveEnabled, hasFilePath, isInScope, _.overSome([isFilePathWhitelisted, _.overEvery([noWhitelistGlobsPresent, filePathDoesNotMatchBlacklistGlobs])]), isFilePathNotEslintignored, _.overSome([_.negate(isDisabledIfNotInPackageJson), isPrettierInPackageJson])]);
+var isFilePathNotPrettierIgnored = _.flow(getCurrentFilePath, _.negate(isFilePathPrettierIgnored));
+
+var isPrettierConfigPresent = function isPrettierConfigPresent(editor) {
+  return !!getPrettierInstance(editor).resolveConfig.sync && _.flow(getCurrentFilePath, getPrettierInstance(editor).resolveConfig.sync, _.negate(_.isNil))(editor);
+};
+
+var shouldFormatOnSave = _.overEvery([isFormatOnSaveEnabled, hasFilePath, isInScope, _.overSome([isFilePathWhitelisted, _.overEvery([noWhitelistGlobsPresent, filePathDoesNotMatchBlacklistGlobs])]), isFilePathNotEslintignored, isFilePathNotPrettierIgnored, _.overSome([_.negate(isDisabledIfNotInPackageJson), isPrettierInPackageJson]), _.overSome([_.negate(isDisabledIfNoConfigFile), isPrettierConfigPresent])]);
 
 module.exports = shouldFormatOnSave;
\ No newline at end of file
diff --git a/dist/helpers/atomRelated.js b/dist/helpers/atomRelated.js
new file mode 100644
index 0000000..08e9fee
--- /dev/null
+++ b/dist/helpers/atomRelated.js
@@ -0,0 +1,17 @@
+'use strict';
+
+var Point = require('atom-text-buffer-point');
+var Range = require('atom-text-buffer-range');
+
+var createPoint = function createPoint(row, column) {
+  return new Point(row, column);
+};
+
+var createRange = function createRange(start, end) {
+  return new Range(start, end);
+};
+
+module.exports = {
+  createPoint: createPoint,
+  createRange: createRange
+};
\ No newline at end of file
diff --git a/dist/helpers/general.js b/dist/helpers/general.js
new file mode 100644
index 0000000..0968d58
--- /dev/null
+++ b/dist/helpers/general.js
@@ -0,0 +1,35 @@
+'use strict';
+
+var _ = require('lodash/fp');
+var ignore = require('ignore');
+var path = require('path');
+
+var _require = require('atom-linter'),
+    findCached = _require.findCached;
+
+var isPresent = function isPresent(target) {
+  return !!target && (typeof target.length === 'undefined' || target.length > 0);
+};
+
+var someGlobsMatchFilePath = function someGlobsMatchFilePath(globs, filePath) {
+  return isPresent(filePath) && ignore().add(globs).ignores(filePath);
+};
+
+var safePathParse = function safePathParse(filePath) {
+  return typeof filePath === 'string' && filePath.length > 0 ? path.parse(filePath) : undefined;
+};
+
+var getDirFromFilePath = _.flow(safePathParse, _.get('dir'));
+
+var findCachedFromFilePath = function findCachedFromFilePath(filePath, name) {
+  return _.flow(getDirFromFilePath, function (dirPath) {
+    return isPresent(dirPath) ? findCached(dirPath, name) : undefined;
+  })(filePath);
+};
+
+module.exports = {
+  isPresent: isPresent,
+  someGlobsMatchFilePath: someGlobsMatchFilePath,
+  getDirFromFilePath: getDirFromFilePath,
+  findCachedFromFilePath: findCachedFromFilePath
+};
\ No newline at end of file
diff --git a/dist/executePrettier/getPrettierInstance.js b/dist/helpers/getPrettierInstance.js
similarity index 93%
rename from dist/executePrettier/getPrettierInstance.js
rename to dist/helpers/getPrettierInstance.js
index d4e2282..87f28cd 100644
--- a/dist/executePrettier/getPrettierInstance.js
+++ b/dist/helpers/getPrettierInstance.js
@@ -1,15 +1,16 @@
 'use strict';
 
 var _ = require('lodash/fp');
-var path = require('path');
 var bundledPrettier = require('prettier');
 
 var _require = require('../editorInterface'),
     getCurrentFilePath = _require.getCurrentFilePath;
 
-var _require2 = require('../helpers'),
+var _require2 = require('./general'),
     findCachedFromFilePath = _require2.findCachedFromFilePath;
 
+var path = require('path');
+
 var PRETTIER_INDEX_PATH = path.join('node_modules', 'prettier', 'index.js');
 
 var getLocalPrettierPath = function getLocalPrettierPath(filePath) {
diff --git a/dist/helpers/index.js b/dist/helpers/index.js
index e420113..9a9b6e4 100644
--- a/dist/helpers/index.js
+++ b/dist/helpers/index.js
@@ -1,48 +1,11 @@
 'use strict';
 
-var _ = require('lodash/fp');
-var path = require('path');
-var ignore = require('ignore');
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
 
-var _require = require('atom-linter'),
-    findCached = _require.findCached;
+var getPrettierInstance = require('./getPrettierInstance');
+var general = require('./general');
+var atomRelated = require('./atomRelated');
 
-var Point = require('atom-text-buffer-point');
-var Range = require('atom-text-buffer-range');
-
-var isPresent = function isPresent(target) {
-  return !!target && (typeof target.length === 'undefined' || target.length > 0);
-};
-
-var safePathParse = function safePathParse(filePath) {
-  return typeof filePath === 'string' && filePath.length > 0 ? path.parse(filePath) : undefined;
-};
-
-var getDirFromFilePath = _.flow(safePathParse, _.get('dir'));
-
-var someGlobsMatchFilePath = function someGlobsMatchFilePath(globs, filePath) {
-  return isPresent(filePath) && ignore().add(globs).ignores(filePath);
-};
-
-var findCachedFromFilePath = function findCachedFromFilePath(filePath, name) {
-  return _.flow(getDirFromFilePath, function (dirPath) {
-    return isPresent(dirPath) ? findCached(dirPath, name) : undefined;
-  })(filePath);
-};
-
-var createPoint = function createPoint(row, column) {
-  return new Point(row, column);
-};
-
-var createRange = function createRange(start, end) {
-  return new Range(start, end);
-};
-
-module.exports = {
-  isPresent: isPresent,
-  getDirFromFilePath: getDirFromFilePath,
-  someGlobsMatchFilePath: someGlobsMatchFilePath,
-  findCachedFromFilePath: findCachedFromFilePath,
-  createRange: createRange,
-  createPoint: createPoint
-};
\ No newline at end of file
+module.exports = _extends({}, general, atomRelated, {
+  getPrettierInstance: getPrettierInstance
+});
\ No newline at end of file
diff --git a/flow-typed/npm/prettier-eslint-cli_vx.x.x.js b/flow-typed/npm/prettier-eslint-cli_vx.x.x.js
index 093bf48..e89ff46 100644
--- a/flow-typed/npm/prettier-eslint-cli_vx.x.x.js
+++ b/flow-typed/npm/prettier-eslint-cli_vx.x.x.js
@@ -1,5 +1,5 @@
-// flow-typed signature: bca8e491121335b0458552e2f67adfa7
-// flow-typed version: <<STUB>>/prettier-eslint-cli_v^4.1.1/flow_v0.53.1
+// flow-typed signature: 43d71777e4b6a3fe34a2bd5cc3fba5d3
+// flow-typed version: <<STUB>>/prettier-eslint-cli_v^4.2.1/flow_v0.53.1
 
 /**
  * This is an autogenerated libdef stub for:
diff --git a/flow-typed/npm/prettier-eslint_vx.x.x.js b/flow-typed/npm/prettier-eslint_vx.x.x.js
index 9a3665e..f4067ff 100644
--- a/flow-typed/npm/prettier-eslint_vx.x.x.js
+++ b/flow-typed/npm/prettier-eslint_vx.x.x.js
@@ -1,5 +1,5 @@
-// flow-typed signature: d589d1559b7dbb7c4a1b5ceb1ae1ee2c
-// flow-typed version: <<STUB>>/prettier-eslint_v^6.4.2/flow_v0.53.1
+// flow-typed signature: 53f2950100380351eb877aa31066b00f
+// flow-typed version: <<STUB>>/prettier-eslint_v^8.1.0/flow_v0.53.1
 
 /**
  * This is an autogenerated libdef stub for:
diff --git a/flow-typed/npm/prettier_vx.x.x.js b/flow-typed/npm/prettier_vx.x.x.js
index a5e8be4..7445d52 100644
--- a/flow-typed/npm/prettier_vx.x.x.js
+++ b/flow-typed/npm/prettier_vx.x.x.js
@@ -1,5 +1,5 @@
-// flow-typed signature: fcaaf74b7566b8ad352783ee583ce4ce
-// flow-typed version: <<STUB>>/prettier_v^1.5.3/flow_v0.53.1
+// flow-typed signature: d08c177f37ef2761707069766b205157
+// flow-typed version: <<STUB>>/prettier_v^1.7.0/flow_v0.53.1
 
 /**
  * This is an autogenerated libdef stub for:
@@ -38,10 +38,6 @@ declare module 'prettier/parser-graphql' {
   declare module.exports: any;
 }
 
-declare module 'prettier/parser-json' {
-  declare module.exports: any;
-}
-
 declare module 'prettier/parser-parse5' {
   declare module.exports: any;
 }
@@ -73,9 +69,6 @@ declare module 'prettier/parser-flow.js' {
 declare module 'prettier/parser-graphql.js' {
   declare module.exports: $Exports<'prettier/parser-graphql'>;
 }
-declare module 'prettier/parser-json.js' {
-  declare module.exports: $Exports<'prettier/parser-json'>;
-}
 declare module 'prettier/parser-parse5.js' {
   declare module.exports: $Exports<'prettier/parser-parse5'>;
 }
diff --git a/package.json b/package.json
index edf9dd2..f243936 100644
--- a/package.json
+++ b/package.json
@@ -29,8 +29,8 @@
     "ignore": "^3.3.4",
     "lodash": "^4.17.4",
     "loophole": "^1.1.0",
-    "prettier": "^1.5.3",
-    "prettier-eslint": "^6.4.2",
+    "prettier": "^1.7.0",
+    "prettier-eslint": "^8.1.0",
     "read-pkg-up": "^2.0.0"
   },
   "devDependencies": {
diff --git a/src/atomInterface/index.js b/src/atomInterface/index.js
index 583e35a..f7a0178 100644
--- a/src/atomInterface/index.js
+++ b/src/atomInterface/index.js
@@ -26,6 +26,8 @@ const isFormatOnSaveEnabled = () => getConfigOption('formatOnSaveOptions.enabled
 const isDisabledIfNotInPackageJson = () =>
   getConfigOption('formatOnSaveOptions.isDisabledIfNotInPackageJson');
 
+const isDisabledIfNoConfigFile = () => getConfigOption('formatOnSaveOptions.isDisabledIfNoConfigFile');
+
 const shouldRespectEslintignore = () => getConfigOption('formatOnSaveOptions.respectEslintignore');
 
 const getJavascriptScopes = () => getConfigOption('formatOnSaveOptions.javascriptScopes');
@@ -106,6 +108,7 @@ module.exports = {
   getAllScopes,
   getWhitelistedGlobs,
   isDisabledIfNotInPackageJson,
+  isDisabledIfNoConfigFile,
   isFormatOnSaveEnabled,
   isLinterEslintAutofixEnabled,
   runLinter,
diff --git a/src/config-schema.json b/src/config-schema.json
index d6b5c73..e0112da 100644
--- a/src/config-schema.json
+++ b/src/config-schema.json
@@ -1,14 +1,16 @@
 {
   "useEslint": {
     "title": "ESLint Integration",
-    "description": "Use [prettier-eslint](https://github.com/prettier/prettier-eslint) to infer your Prettier settings based on your ESLint config. If we cannot infer a Prettier setting from your ESLint config (or if there is none in the current project), we will fallback to using your settings in the *Prettier Options* section.<br><br>**Note:** If you enable *Format on Save*, we recommend disabling ESlint's auto-fix to prevent fixing your code twice.",
+    "description":
+      "Use [prettier-eslint](https://github.com/prettier/prettier-eslint) to infer your Prettier settings based on your ESLint config. If we cannot infer a Prettier setting from your ESLint config (or if there is none in the current project), we will fallback to using your settings in the *Prettier Options* section.<br><br>**Note:** If you enable *Format on Save*, we recommend disabling ESlint's auto-fix to prevent fixing your code twice.",
     "type": "boolean",
     "default": false,
     "order": 1
   },
   "useEditorConfig": {
     "title": "EditorConfig Integration",
-    "description": "Use [EditorConfig](http://editorconfig.org/) configuration to load project-based settings for Prettier formatting.<br>Takes precedence over your settings. The following settings will be overriden if they are found in your `.editorconfig`: **Use tabs**, **Tab width**, **Print width**.",
+    "description":
+      "Use [EditorConfig](http://editorconfig.org/) configuration to load project-based settings for Prettier formatting.<br>Takes precedence over your settings. The following settings will be overriden if they are found in your `.editorconfig`: **Use tabs**, **Tab width**, **Print width**.",
     "type": "boolean",
     "default": true,
     "order": 2
@@ -41,7 +43,8 @@
       },
       "javascriptScopes": {
         "title": "JavaScript Scopes",
-        "description": "Select which files containing JavaScript should be formatted.<br>Use the command `Editor: Log Cursor Scope` to determine the scopes for a file.",
+        "description":
+          "Select which files containing JavaScript should be formatted.<br>Use the command `Editor: Log Cursor Scope` to determine the scopes for a file.",
         "type": "array",
         "default": [
           "source.js",
@@ -59,7 +62,8 @@
       },
       "typescriptScopes": {
         "title": "TypeScript Scopes",
-        "description": "Select which files containing TypeScript should be formatted.<br>Use the command `Editor: Log Cursor Scope` to determine the scopes for a file.",
+        "description":
+          "Select which files containing TypeScript should be formatted.<br>Use the command `Editor: Log Cursor Scope` to determine the scopes for a file.",
         "type": "array",
         "default": ["source.ts", "source.tsx", "source.ts.tsx"],
         "items": {
@@ -69,7 +73,8 @@
       },
       "cssScopes": {
         "title": "CSS Scopes",
-        "description": "Select which files containing CSS should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
+        "description":
+          "Select which files containing CSS should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
         "type": "array",
         "default": ["source.css", "source.less", "source.css.less", "source.scss", "source.css.scss"],
         "items": {
@@ -79,7 +84,8 @@
       },
       "jsonScopes": {
         "title": "JSON Scopes",
-        "description": "Select which files containing JSON should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
+        "description":
+          "Select which files containing JSON should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
         "type": "array",
         "default": ["source.json"],
         "items": {
@@ -89,7 +95,8 @@
       },
       "graphQlScopes": {
         "title": "GraphQL Scopes",
-        "description": "Select which files containing GraphQL should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
+        "description":
+          "Select which files containing GraphQL should be formatted.<br>Use `Editor: Log Cursor Scope` to determine the scopes for a file.",
         "type": "array",
         "default": ["source.graphql"],
         "items": {
@@ -99,24 +106,35 @@
       },
       "excludedGlobs": {
         "title": "Exclude (list of globs)",
-        "description": "A list of file globs to exclude from formatting on save (takes precedence over scopes). Use commas to separate each glob.",
+        "description":
+          "A list of file globs to exclude from formatting on save (takes precedence over scopes). Use commas to separate each glob.",
         "type": "array",
         "default": [],
         "order": 9
       },
       "whitelistedGlobs": {
         "title": "Include (list of globs)",
-        "description": "A list of file globs to always format on save (takes precedence over scopes and excluded globs). Use commas to separate each glob.<br><br>**Note:** If there are globs in this list, files not matching the globs will not be formatted on save, regardless of other options.",
+        "description":
+          "A list of file globs to always format on save (takes precedence over scopes and excluded globs). Use commas to separate each glob.<br><br>**Note:** If there are globs in this list, files not matching the globs will not be formatted on save, regardless of other options.",
         "type": "array",
         "default": [],
         "order": 10
       },
       "isDisabledIfNotInPackageJson": {
         "title": "Only format if Prettier is found in your project's dependencies",
-        "description": "Only format on save when `prettier` (or `prettier-eslint`/`prettier-eslint-cli` if using *ESLint integration*) is in your project's `package.json` (dependencies or devDependencies)",
+        "description":
+          "Only format on save when `prettier` (or `prettier-eslint`/`prettier-eslint-cli` if using *ESLint integration*) is in your project's `package.json` (dependencies or devDependencies)",
         "type": "boolean",
         "default": false,
         "order": 11
+      },
+      "isDisabledIfNoConfigFile": {
+        "title": "Only format if a Prettier config is found",
+        "description":
+          "Only format on save if we find a `.prettierrc` file (written in YAML or JSON), a `prettier.config.js` file that exports an object, or a 'prettier' key in your `package.json` file. <br><br>**Note:** You must have at least one valid rule in order for your config to be considered present.",
+        "type": "boolean",
+        "default": false,
+        "order": 12
       }
     }
   },
@@ -183,7 +201,8 @@
       },
       "parser": {
         "title": "JavaScript Parser",
-        "description": "Choose which [supported parser](https://www.npmjs.com/package/prettier#language-support) to use. (Does not apply to TypeScript, CSS or JSON)",
+        "description":
+          "Choose which [supported parser](https://www.npmjs.com/package/prettier#language-support) to use. (Does not apply to TypeScript, CSS or JSON)",
         "type": "string",
         "default": "babylon",
         "enum": ["babylon", "flow"],
diff --git a/src/executePrettier/buildPrettierOptions.js b/src/executePrettier/buildPrettierOptions.js
index d33310e..ce909c9 100644
--- a/src/executePrettier/buildPrettierOptions.js
+++ b/src/executePrettier/buildPrettierOptions.js
@@ -9,6 +9,7 @@ const {
 } = require('../editorInterface');
 const { shouldUseEditorConfig, getPrettierOptions, getAtomTabLength } = require('../atomInterface');
 const buildEditorConfigOptions = require('./buildEditorConfigOptions');
+const { getPrettierInstance } = require('../helpers');
 
 const isDefined: (x: any) => boolean = _.negate(_.isNil);
 
@@ -22,6 +23,16 @@ const buildEditorConfigOptionsIfAppropriate: (editor: TextEditor) => ?{} = _.flo
   _.cond([[isAppropriateToBuildEditorConfigOptions, buildEditorConfigOptions]]),
 );
 
+const getPrettierConfigOptions: (editor: TextEditor) => ?{} = _.cond([
+  [
+    _.flow(getCurrentFilePath, isDefined),
+    editor =>
+      isDefined(getPrettierInstance(editor).resolveConfig.sync)
+        ? getPrettierInstance(editor).resolveConfig.sync(getCurrentFilePath(editor))
+        : null,
+  ],
+]);
+
 const buildPrettierOptions = (editor: TextEditor) => {
   const optionsFromSettings = getPrettierOptions();
 
@@ -49,6 +60,7 @@ const buildPrettierOptions = (editor: TextEditor) => {
   return {
     ...optionsFromSettings,
     ...buildEditorConfigOptionsIfAppropriate(editor),
+    ...getPrettierConfigOptions(editor),
   };
 };
 
diff --git a/src/executePrettier/executePrettierOnBufferRange.js b/src/executePrettier/executePrettierOnBufferRange.js
index e12bda9..bffaf97 100644
--- a/src/executePrettier/executePrettierOnBufferRange.js
+++ b/src/executePrettier/executePrettierOnBufferRange.js
@@ -4,7 +4,7 @@ const prettierEslint = require('prettier-eslint');
 const { allowUnsafeNewFunction } = require('loophole');
 
 const { shouldUseEslint, runLinter } = require('../atomInterface');
-const getPrettierInstance = require('./getPrettierInstance');
+const { getPrettierInstance } = require('../helpers');
 const buildPrettierEslintOptions = require('./buildPrettierEslintOptions');
 const buildPrettierOptions = require('./buildPrettierOptions');
 const handleError = require('./handleError');
diff --git a/src/formatOnSave/isFilePathPrettierIgnored.js b/src/formatOnSave/isFilePathPrettierIgnored.js
new file mode 100644
index 0000000..9758a2f
--- /dev/null
+++ b/src/formatOnSave/isFilePathPrettierIgnored.js
@@ -0,0 +1,32 @@
+// @flow
+const _ = require('lodash/fp');
+const path = require('path');
+const fs = require('fs');
+const { findCachedFromFilePath, getDirFromFilePath, someGlobsMatchFilePath } = require('../helpers');
+
+const LINE_SEPERATOR_REGEX = /(\r|\n|\r\n)/;
+
+const getNearestPrettierIgnorePath = (filePath: FilePath): ?FilePath =>
+  findCachedFromFilePath(filePath, '.prettierignore');
+
+const safeRelativePath = _.curry(
+  (from: ?FilePath, to: ?FilePath): ?FilePath => (!!from && !!to ? path.relative(from, to) : undefined),
+);
+
+const getFilePathRelativeToPrettierIgnore = (filePath: FilePath): ?FilePath =>
+  _.flow(getNearestPrettierIgnorePath, getDirFromFilePath, safeRelativePath(_, filePath))(filePath);
+
+const getLinesFromFilePath = (filePath: ?FilePath) =>
+  !!filePath && filePath.length > 0 ? fs.readFileSync(filePath, 'utf8').split(LINE_SEPERATOR_REGEX) : [];
+
+const getIgnoredGlobsFromNearestPrettierIgnore: (filePath: FilePath) => Globs = _.flow(
+  getNearestPrettierIgnorePath,
+  getLinesFromFilePath,
+);
+
+const isFilePathPrettierIgnored: (filePath: FilePath) => boolean = _.flow(
+  _.over([getIgnoredGlobsFromNearestPrettierIgnore, getFilePathRelativeToPrettierIgnore]),
+  _.spread(someGlobsMatchFilePath),
+);
+
+module.exports = isFilePathPrettierIgnored;
diff --git a/src/formatOnSave/shouldFormatOnSave.js b/src/formatOnSave/shouldFormatOnSave.js
index e31d3b2..17f914a 100644
--- a/src/formatOnSave/shouldFormatOnSave.js
+++ b/src/formatOnSave/shouldFormatOnSave.js
@@ -1,6 +1,6 @@
 // @flow
 const _ = require('lodash/fp');
-const { someGlobsMatchFilePath } = require('../helpers');
+const { someGlobsMatchFilePath, getPrettierInstance } = require('../helpers');
 const { getCurrentFilePath, getCurrentScope } = require('../editorInterface');
 const {
   isFormatOnSaveEnabled,
@@ -8,8 +8,10 @@ const {
   getExcludedGlobs,
   getWhitelistedGlobs,
   isDisabledIfNotInPackageJson,
+  isDisabledIfNoConfigFile,
 } = require('../atomInterface');
 const isFilePathEslintignored = require('./isFilePathEslintIgnored');
+const isFilePathPrettierIgnored = require('./isFilePathPrettierIgnored');
 const isPrettierInPackageJson = require('./isPrettierInPackageJson');
 
 const hasFilePath = (editor: TextEditor) => !!getCurrentFilePath(editor);
@@ -35,6 +37,15 @@ const isFilePathNotEslintignored: (editor: TextEditor) => boolean = _.flow(
   _.negate(isFilePathEslintignored),
 );
 
+const isFilePathNotPrettierIgnored: (editor: TextEditor) => boolean = _.flow(
+  getCurrentFilePath,
+  _.negate(isFilePathPrettierIgnored),
+);
+
+const isPrettierConfigPresent = (editor: TextEditor): boolean =>
+  !!getPrettierInstance(editor).resolveConfig.sync &&
+  _.flow(getCurrentFilePath, getPrettierInstance(editor).resolveConfig.sync, _.negate(_.isNil))(editor);
+
 const shouldFormatOnSave: (editor: TextEditor) => boolean = _.overEvery([
   isFormatOnSaveEnabled,
   hasFilePath,
@@ -44,7 +55,9 @@ const shouldFormatOnSave: (editor: TextEditor) => boolean = _.overEvery([
     _.overEvery([noWhitelistGlobsPresent, filePathDoesNotMatchBlacklistGlobs]),
   ]),
   isFilePathNotEslintignored,
+  isFilePathNotPrettierIgnored,
   _.overSome([_.negate(isDisabledIfNotInPackageJson), isPrettierInPackageJson]),
+  _.overSome([_.negate(isDisabledIfNoConfigFile), isPrettierConfigPresent]),
 ]);
 
 module.exports = shouldFormatOnSave;
diff --git a/src/helpers/atomRelated.js b/src/helpers/atomRelated.js
new file mode 100644
index 0000000..79d50ce
--- /dev/null
+++ b/src/helpers/atomRelated.js
@@ -0,0 +1,13 @@
+// @flow
+const Point = require('atom-text-buffer-point');
+const Range = require('atom-text-buffer-range');
+
+const createPoint = (row: number, column: number): Point => new Point(row, column);
+
+const createRange = (start: Point | [number, number], end: Point | [number, number]): Range =>
+  new Range(start, end);
+
+module.exports = {
+  createPoint,
+  createRange,
+};
diff --git a/src/helpers/general.js b/src/helpers/general.js
new file mode 100644
index 0000000..7a4866f
--- /dev/null
+++ b/src/helpers/general.js
@@ -0,0 +1,32 @@
+// @flow
+const _ = require('lodash/fp');
+const ignore = require('ignore');
+const path = require('path');
+const { findCached } = require('atom-linter');
+
+const isPresent = (target: any): boolean =>
+  !!target && (typeof target.length === 'undefined' || target.length > 0);
+
+const someGlobsMatchFilePath = (globs: Globs, filePath: ?FilePath) =>
+  isPresent(filePath) &&
+  ignore()
+    .add(globs)
+    .ignores(filePath);
+
+const safePathParse = (filePath: FilePath) =>
+  typeof filePath === 'string' && filePath.length > 0 ? path.parse(filePath) : undefined;
+
+const getDirFromFilePath: (filePath: ?FilePath) => ?FilePath = _.flow(safePathParse, _.get('dir'));
+
+const findCachedFromFilePath = (filePath: ?FilePath, name: string | Array<string>): ?FilePath =>
+  _.flow(
+    getDirFromFilePath,
+    (dirPath: FilePath): ?FilePath => (isPresent(dirPath) ? findCached(dirPath, name) : undefined),
+  )(filePath);
+
+module.exports = {
+  isPresent,
+  someGlobsMatchFilePath,
+  getDirFromFilePath,
+  findCachedFromFilePath,
+};
diff --git a/src/executePrettier/getPrettierInstance.js b/src/helpers/getPrettierInstance.js
similarity index 94%
rename from src/executePrettier/getPrettierInstance.js
rename to src/helpers/getPrettierInstance.js
index b1980b3..d92bfdc 100644
--- a/src/executePrettier/getPrettierInstance.js
+++ b/src/helpers/getPrettierInstance.js
@@ -1,9 +1,9 @@
 // @flow
 const _ = require('lodash/fp');
-const path = require('path');
 const bundledPrettier = require('prettier');
 const { getCurrentFilePath } = require('../editorInterface');
-const { findCachedFromFilePath } = require('../helpers');
+const { findCachedFromFilePath } = require('./general');
+const path = require('path');
 
 const PRETTIER_INDEX_PATH = path.join('node_modules', 'prettier', 'index.js');
 
diff --git a/src/executePrettier/getPrettierInstance.test.js b/src/helpers/getPrettierInstance.test.js
similarity index 100%
rename from src/executePrettier/getPrettierInstance.test.js
rename to src/helpers/getPrettierInstance.test.js
diff --git a/src/helpers/index.js b/src/helpers/index.js
index e82324a..1299d30 100644
--- a/src/helpers/index.js
+++ b/src/helpers/index.js
@@ -1,38 +1,10 @@
 // @flow
-const _ = require('lodash/fp');
-const path = require('path');
-const ignore = require('ignore');
-const { findCached } = require('atom-linter');
-const Point = require('atom-text-buffer-point');
-const Range = require('atom-text-buffer-range');
-
-const isPresent = (target: any): boolean =>
-  !!target && (typeof target.length === 'undefined' || target.length > 0);
-
-const safePathParse = (filePath: FilePath) =>
-  typeof filePath === 'string' && filePath.length > 0 ? path.parse(filePath) : undefined;
-
-const getDirFromFilePath: (filePath: ?FilePath) => ?FilePath = _.flow(safePathParse, _.get('dir'));
-
-const someGlobsMatchFilePath = (globs: Globs, filePath: ?FilePath) =>
-  isPresent(filePath) && ignore().add(globs).ignores(filePath);
-
-const findCachedFromFilePath = (filePath: ?FilePath, name: string | Array<string>): ?FilePath =>
-  _.flow(
-    getDirFromFilePath,
-    (dirPath: FilePath): ?FilePath => (isPresent(dirPath) ? findCached(dirPath, name) : undefined),
-  )(filePath);
-
-const createPoint = (row: number, column: number): Point => new Point(row, column);
-
-const createRange = (start: Point | [number, number], end: Point | [number, number]): Range =>
-  new Range(start, end);
+const getPrettierInstance = require('./getPrettierInstance');
+const general = require('./general');
+const atomRelated = require('./atomRelated');
 
 module.exports = {
-  isPresent,
-  getDirFromFilePath,
-  someGlobsMatchFilePath,
-  findCachedFromFilePath,
-  createRange,
-  createPoint,
+  ...general,
+  ...atomRelated,
+  getPrettierInstance,
 };
diff --git a/tests/fixtures/doesNotMatchPrettierignore.js b/tests/fixtures/doesNotMatchPrettierignore.js
new file mode 100644
index 0000000..e69de29
diff --git a/tests/fixtures/matchesPrettierignore.js b/tests/fixtures/matchesPrettierignore.js
new file mode 100644
index 0000000..e69de29
diff --git a/yarn.lock b/yarn.lock
index 1d2a733..f4bce13 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2460,6 +2460,10 @@ indent-string@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.1.0.tgz#08ff4334603388399b329e6b9538dc7a3cf5de7d"
 
+indent-string@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
+
 inflight@^1.0.4:
   version "1.0.6"
   resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@@ -3217,6 +3221,10 @@ lodash.merge@^4.6.0:
   version "4.6.0"
   resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5"
 
+lodash.unescape@4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c"
+
 lodash.uniq@^4.5.0:
   version "4.5.0"
   resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
@@ -3823,27 +3831,29 @@ prettier-eslint@^6.0.0:
     pretty-format "^20.0.3"
     require-relative "^0.8.7"
 
-prettier-eslint@^6.4.2:
-  version "6.4.2"
-  resolved "https://registry.yarnpkg.com/prettier-eslint/-/prettier-eslint-6.4.2.tgz#9bafd9549e0827396c75848e8dbeb65525b9096e"
+prettier-eslint@^8.1.0:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/prettier-eslint/-/prettier-eslint-8.1.0.tgz#8b0366e180c0d4ec1f76ccd635bb20e3f47bc156"
   dependencies:
     common-tags "^1.4.0"
     dlv "^1.1.0"
-    eslint "^3.19.0"
-    indent-string "^3.1.0"
+    eslint "^4.5.0"
+    indent-string "^3.2.0"
     lodash.merge "^4.6.0"
     loglevel-colored-level-prefix "^1.0.0"
-    prettier "^1.5.0"
+    prettier "^1.7.0"
     pretty-format "^20.0.3"
     require-relative "^0.8.7"
+    typescript "^2.4.2"
+    typescript-eslint-parser "^7.0.0"
 
 prettier@^1.5.0:
   version "1.5.2"
   resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.5.2.tgz#7ea0751da27b93bfb6cecfcec509994f52d83bb3"
 
-prettier@^1.5.3:
-  version "1.5.3"
-  resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.5.3.tgz#59dadc683345ec6b88f88b94ed4ae7e1da394bfe"
+prettier@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.7.0.tgz#47481588f41f7c90f63938feb202ac82554e7150"
 
 pretty-format@^20.0.3:
   version "20.0.3"
@@ -4302,7 +4312,7 @@ sb-promisify@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/sb-promisify/-/sb-promisify-2.0.1.tgz#86c6cb4e1780c9b38c6fbe7e7873f8ab9677ce2a"
 
-"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@~5.3.0:
+"semver@2 || 3 || 4 || 5", semver@5.3.0, semver@^5.1.0, semver@^5.3.0, semver@~5.3.0:
   version "5.3.0"
   resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
 
@@ -4717,6 +4727,17 @@ typedarray@^0.0.6:
   version "0.0.6"
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
 
+typescript-eslint-parser@^7.0.0:
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/typescript-eslint-parser/-/typescript-eslint-parser-7.0.0.tgz#be57d8768e37707af825e339ea2af18d7393cabb"
+  dependencies:
+    lodash.unescape "4.0.1"
+    semver "5.3.0"
+
+typescript@^2.4.2:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.5.2.tgz#038a95f7d9bbb420b1bf35ba31d4c5c1dd3ffe34"
+
 uglify-js@^2.6:
   version "2.8.7"
   resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.7.tgz#e0391911507b6d2e05697a528f1686e90a11b160"


Test patch:
diff --git a/src/executePrettier/buildPrettierOptions.test.js b/src/executePrettier/buildPrettierOptions.test.js
index 31420d3..e58a6cb 100644
--- a/src/executePrettier/buildPrettierOptions.test.js
+++ b/src/executePrettier/buildPrettierOptions.test.js
@@ -1,6 +1,7 @@
 jest.mock('../atomInterface');
 jest.mock('../editorInterface');
 jest.mock('./buildEditorConfigOptions');
+jest.mock('../helpers');
 
 const { getPrettierOptions, getAtomTabLength, shouldUseEditorConfig } = require('../atomInterface');
 const {
@@ -13,6 +14,11 @@ const {
 const buildEditorConfigOptions = require('./buildEditorConfigOptions');
 const buildMockEditor = require('../../tests/mocks/textEditor');
 const buildPrettierOptions = require('./buildPrettierOptions');
+const { getPrettierInstance } = require('../helpers');
+
+beforeEach(() => {
+  getPrettierInstance.mockImplementation(() => ({ resolveConfig: { sync: jest.fn() } }));
+});
 
 it('returns prettier options', () => {
   const editor = buildMockEditor();
@@ -102,3 +108,17 @@ it('overrides values with editorconfig values if editor config is enabled', () =
 
   expect(actual).toEqual(fakeEditorConfigOptions);
 });
+
+it('overrides values with prettier config values if one exists', () => {
+  const editor = buildMockEditor();
+  const fakePrettierOptions = { tabWidth: 2, printWidth: 80, useTabs: false };
+  const fakePrettierConfigOptions = { tabWidth: 4, printWidth: 100, useTabs: true };
+  const mockPrettierInstance = { resolveConfig: { sync: jest.fn(() => fakePrettierConfigOptions) } };
+  getPrettierInstance.mockImplementation(() => mockPrettierInstance);
+  getCurrentFilePath.mockImplementation(() => 'parent-dir/foo.js');
+  getPrettierOptions.mockImplementation(() => fakePrettierOptions);
+
+  const actual = buildPrettierOptions(editor);
+
+  expect(actual).toEqual(fakePrettierConfigOptions);
+});
diff --git a/src/executePrettier/executePrettierOnBufferRange.test.js b/src/executePrettier/executePrettierOnBufferRange.test.js
index c01968a..37e7396 100644
--- a/src/executePrettier/executePrettierOnBufferRange.test.js
+++ b/src/executePrettier/executePrettierOnBufferRange.test.js
@@ -2,7 +2,7 @@ jest.mock('prettier-eslint');
 jest.mock('prettier');
 jest.mock('../atomInterface');
 jest.mock('../editorInterface');
-jest.mock('./getPrettierInstance');
+jest.mock('../helpers');
 jest.mock('./buildPrettierOptions');
 jest.mock('./buildPrettierEslintOptions');
 jest.mock('./handleError');
@@ -11,7 +11,7 @@ const prettier = require('prettier');
 const prettierEslint = require('prettier-eslint');
 const { shouldUseEslint, runLinter } = require('../atomInterface');
 const { getCurrentFilePath } = require('../editorInterface');
-const getPrettierInstance = require('./getPrettierInstance');
+const { getPrettierInstance } = require('../helpers');
 const buildPrettierEslintOptions = require('./buildPrettierEslintOptions');
 const buildPrettierOptions = require('./buildPrettierOptions');
 const handleError = require('./handleError');
diff --git a/src/formatOnSave/isFilePathPrettierIgnored.test.js b/src/formatOnSave/isFilePathPrettierIgnored.test.js
new file mode 100644
index 0000000..170efc9
--- /dev/null
+++ b/src/formatOnSave/isFilePathPrettierIgnored.test.js
@@ -0,0 +1,26 @@
+const path = require('path');
+const isFilePathPrettierIgnored = require('./isFilePathPrettierIgnored');
+
+it('returns true if the filepath is prettierignored', () => {
+  const filePath = path.join(__dirname, '..', '..', 'tests', 'fixtures', 'matchesPrettierignore.js');
+
+  const actual = isFilePathPrettierIgnored(filePath);
+
+  expect(actual).toBe(true);
+});
+
+it('returns false if the filepath is not prettierignored', () => {
+  const filePath = path.join(__dirname, '..', '..', 'tests', 'fixtures', 'doesNotMatchPrettierignore.js');
+
+  const actual = isFilePathPrettierIgnored(filePath);
+
+  expect(actual).toBe(false);
+});
+
+it('returns false if no .prettierignore file can be found', () => {
+  const filePath = '';
+
+  const actual = isFilePathPrettierIgnored(filePath);
+
+  expect(actual).toBe(false);
+});
diff --git a/src/formatOnSave/shouldFormatOnSave.test.js b/src/formatOnSave/shouldFormatOnSave.test.js
index 0e29762..3f0e324 100644
--- a/src/formatOnSave/shouldFormatOnSave.test.js
+++ b/src/formatOnSave/shouldFormatOnSave.test.js
@@ -1,18 +1,23 @@
 jest.mock('../editorInterface');
 jest.mock('../atomInterface');
+jest.mock('../helpers/getPrettierInstance');
 jest.mock('./isFilePathEslintIgnored');
+jest.mock('./isFilePathPrettierIgnored');
 jest.mock('./isPrettierInPackageJson');
 
 const createMockTextEditor = require('../../tests/mocks/textEditor');
 const {
   isDisabledIfNotInPackageJson,
+  isDisabledIfNoConfigFile,
   isFormatOnSaveEnabled,
   getExcludedGlobs,
   getWhitelistedGlobs,
   getAllScopes,
 } = require('../atomInterface');
+const getPrettierInstance = require('../helpers/getPrettierInstance');
 const { getCurrentScope, getCurrentFilePath } = require('../editorInterface');
 const isFilePathEslintIgnored = require('./isFilePathEslintIgnored');
+const isFilePathPrettierIgnored = require('./isFilePathPrettierIgnored');
 const shouldFormatOnSave = require('./shouldFormatOnSave');
 const isPrettierInPackageJson = require('./isPrettierInPackageJson');
 
@@ -26,6 +31,7 @@ beforeEach(() => {
   getCurrentFilePath.mockImplementation(() => fakeCurrentFilePath);
   isFilePathEslintIgnored.mockImplementation(() => false);
   isDisabledIfNotInPackageJson.mockImplementation(() => false);
+  isDisabledIfNoConfigFile.mockImplementation(() => false);
 });
 
 it('returns true if should format on save', () => {
@@ -91,6 +97,14 @@ it('returns false if the filepath is eslintignored', () => {
   expect(actual).toBe(false);
 });
 
+it('returns false if the filepath is prettier ignored', () => {
+  isFilePathPrettierIgnored.mockImplementation(() => true);
+
+  const actual = callShouldFormatOnSave();
+
+  expect(actual).toBe(false);
+});
+
 it('returns true if prettier needs to be in package json and is found in package json', () => {
   isDisabledIfNotInPackageJson.mockImplementation(() => true);
   isPrettierInPackageJson.mockImplementation(() => true);
@@ -108,3 +122,25 @@ it("returns false if prettier needs to be in package json and it isn't", () => {
 
   expect(actual).toBe(false);
 });
+
+it("returns true if prettier config file needs to be present and it's found", () => {
+  isDisabledIfNoConfigFile.mockImplementation(() => true);
+  const fakeSync = jest.fn(() => ({ tabWidth: 100 }));
+  getPrettierInstance.mockImplementation(() => ({ resolveConfig: { sync: fakeSync } }));
+
+  const actual = callShouldFormatOnSave();
+
+  expect(actual).toBe(true);
+  expect(fakeSync).toHaveBeenCalledWith(fakeCurrentFilePath);
+});
+
+it("returns false if prettier config file needs to be present and it isn't", () => {
+  isDisabledIfNoConfigFile.mockImplementation(() => true);
+  const fakeSync = jest.fn(() => null);
+  getPrettierInstance.mockImplementation(() => ({ resolveConfig: { sync: fakeSync } }));
+
+  const actual = callShouldFormatOnSave();
+
+  expect(actual).toBe(false);
+  expect(fakeSync).toHaveBeenCalledWith(fakeCurrentFilePath);
+});
diff --git a/tests/fixtures/.prettierignore b/tests/fixtures/.prettierignore
new file mode 100644
index 0000000..3a8ea97
--- /dev/null
+++ b/tests/fixtures/.prettierignore
@@ -0,0 +1,1 @@
+matchesPrettierignore.js