Skip to content
This repository has been archived by the owner on Apr 17, 2023. It is now read-only.

Commit

Permalink
feat(format-on-save): add option to not format on save if prettier no…
Browse files Browse the repository at this point in the history
…t in dependencies

We will look for prettier (prettier-eslint/prettier-eslint-cli if you have the eslint integration
setting enabled) in the package.json nearest to the file being formatted. The dependency can be in
either the "dependencies" or "devDependencies" section.

Resolves #43
  • Loading branch information
robwise committed Jun 8, 2017
1 parent 372524c commit 1a32d47
Show file tree
Hide file tree
Showing 14 changed files with 236 additions and 13 deletions.
5 changes: 5 additions & 0 deletions dist/atomInterface/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ var isFormatOnSaveEnabled = function isFormatOnSaveEnabled() {
return getConfigOption('formatOnSaveOptions.enabled');
};

var isDisabledIfNotInPackageJson = function isDisabledIfNotInPackageJson() {
return getConfigOption('formatOnSaveOptions.isDisabledIfNotInPackageJson');
};

var shouldRespectEslintignore = function shouldRespectEslintignore() {
return getConfigOption('formatOnSaveOptions.respectEslintignore');
};
Expand Down Expand Up @@ -112,6 +116,7 @@ module.exports = {
getPrettierOptions: getPrettierOptions,
getScopes: getScopes,
getWhitelistedGlobs: getWhitelistedGlobs,
isDisabledIfNotInPackageJson: isDisabledIfNotInPackageJson,
isFormatOnSaveEnabled: isFormatOnSaveEnabled,
isLinterEslintAutofixEnabled: isLinterEslintAutofixEnabled,
runLinter: runLinter,
Expand Down
7 changes: 7 additions & 0 deletions dist/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@
"type": "array",
"default": [],
"order": 6
},
"isDisabledIfNotInPackageJson": {
"title": "Only format if prettier is found in your project's dependencies",
"description": "Does not format on save if 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": 7
}
}
},
Expand Down
4 changes: 2 additions & 2 deletions dist/displayDebugInfo/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

var readPkg = require('read-pkg');
var readPkgUp = require('read-pkg-up');
var path = require('path');

var _require = require('../atomInterface'),
Expand All @@ -13,7 +13,7 @@ var getDepPath = function getDepPath(dep) {
};

var getDebugInfo = function getDebugInfo() {
return ('\nAtom version: ' + getAtomVersion() + '\nprettier-atom version: ' + readPkg.sync(path.join(__dirname, '..', '..')).version + '\nprettier version: ' + readPkg.sync(getDepPath('prettier')).version + '\nprettier-eslint version: ' + readPkg.sync(getDepPath('prettier-eslint')).version + '\nprettier-atom configuration: ' + JSON.stringify(getPrettierAtomConfig(), null, 2) + '\n').trim();
return ('\nAtom version: ' + getAtomVersion() + '\nprettier-atom version: ' + readPkgUp.sync(__dirname).version + '\nprettier version: ' + readPkgUp.sync(getDepPath('prettier')).version + '\nprettier-eslint version: ' + readPkgUp.sync(getDepPath('prettier-eslint')).version + '\nprettier-atom configuration: ' + JSON.stringify(getPrettierAtomConfig(), null, 2) + '\n').trim();
};

var displayDebugInfo = function displayDebugInfo() {
Expand Down
10 changes: 9 additions & 1 deletion dist/editorInterface/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
'use strict';

var _ = require('lodash/fp');
var path = require('path');

var EMBEDDED_SCOPES = ['text.html.vue', 'text.html.basic'];

var getBufferRange = function getBufferRange(editor) {
Expand All @@ -18,9 +21,14 @@ var getCurrentFilePath = function getCurrentFilePath(editor) {
return editor.buffer.file ? editor.buffer.file.path : undefined;
};

var getCurrentDir = _.flow(getCurrentFilePath, function (maybeFilePath) {
return typeof maybeFilePath === 'string' ? path.dirname(maybeFilePath) : undefined;
});

module.exports = {
getBufferRange: getBufferRange,
isCurrentScopeEmbeddedScope: isCurrentScopeEmbeddedScope,
getCurrentScope: getCurrentScope,
getCurrentFilePath: getCurrentFilePath
getCurrentFilePath: getCurrentFilePath,
getCurrentDir: getCurrentDir
};
8 changes: 0 additions & 8 deletions dist/executePrettier/getPrettierInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,6 @@ var getLocalPrettierPath = function getLocalPrettierPath(filePath) {
return findCachedFromFilePath(filePath, PRETTIER_INDEX_PATH);
};

// const getLocalPrettierPath = (filePath: ?FilePath): ?FilePath => {
// if (!filePath) return null;
//
// const dirPath = getDirFromFilePath(filePath);
//
// return dirPath ? findCached(dirPath, PRETTIER_INDEX_PATH) : null;
// };

// charypar: This is currently the best way to use local prettier instance.
// Using the CLI introduces a noticeable delay and there is currently no
// way to use prettier as a long-running process for formatting files as needed
Expand Down
30 changes: 30 additions & 0 deletions dist/formatOnSave/isPrettierInPackageJson.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';

var _ = require('lodash/fp');
var readPgkUp = require('read-pkg-up');

var _require = require('../editorInterface'),
getCurrentDir = _require.getCurrentDir;

var _require2 = require('../atomInterface'),
shouldUseEslint = _require2.shouldUseEslint;

var hasPackageDependency = function hasPackageDependency(packageName) {
return _.flow(_.get('pkg.dependencies'), _.has(packageName));
};

var hasPackageDevDependency = function hasPackageDevDependency(packageName) {
return _.flow(_.get('pkg.devDependencies'), _.has(packageName));
};

var hasPackage = function hasPackage(packageName) {
return _.overSome([hasPackageDependency(packageName), hasPackageDevDependency(packageName)]);
};

var readContentsOfNearestPackageJson = _.flow(getCurrentDir, _.set('cwd', _, {}), readPgkUp.sync);

var isPrettierInPackageJson = _.flow(readContentsOfNearestPackageJson, hasPackage('prettier'));

var isPrettierEslintInPackageJson = _.flow(readContentsOfNearestPackageJson, _.overSome([hasPackage('prettier-eslint'), hasPackage('prettier-eslint-cli')]));

module.exports = _.cond([[shouldUseEslint, isPrettierEslintInPackageJson], [_.stubTrue, isPrettierInPackageJson]]);
6 changes: 4 additions & 2 deletions dist/formatOnSave/shouldFormatOnSave.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ var _require3 = require('../atomInterface'),
isFormatOnSaveEnabled = _require3.isFormatOnSaveEnabled,
getScopes = _require3.getScopes,
getExcludedGlobs = _require3.getExcludedGlobs,
getWhitelistedGlobs = _require3.getWhitelistedGlobs;
getWhitelistedGlobs = _require3.getWhitelistedGlobs,
isDisabledIfNotInPackageJson = _require3.isDisabledIfNotInPackageJson;

var isFilePathEslintignored = require('./isFilePathEslintIgnored');
var isPrettierInPackageJson = require('./isPrettierInPackageJson');

var hasFilePath = function hasFilePath(editor) {
return !!getCurrentFilePath(editor);
Expand All @@ -37,6 +39,6 @@ var isFilePathWhitelisted = _.flow(getCurrentFilePath, function (filePath) {

var isFilePathNotEslintignored = _.flow(getCurrentFilePath, _.negate(isFilePathEslintignored));

var shouldFormatOnSave = _.overEvery([isFormatOnSaveEnabled, hasFilePath, isInScope, _.overSome([isFilePathWhitelisted, _.overEvery([noWhitelistGlobsPresent, filePathDoesNotMatchBlacklistGlobs])]), isFilePathNotEslintignored]);
var shouldFormatOnSave = _.overEvery([isFormatOnSaveEnabled, hasFilePath, isInScope, _.overSome([isFilePathWhitelisted, _.overEvery([noWhitelistGlobsPresent, filePathDoesNotMatchBlacklistGlobs])]), isFilePathNotEslintignored, _.overSome([_.negate(isDisabledIfNotInPackageJson), isPrettierInPackageJson])]);

module.exports = shouldFormatOnSave;
4 changes: 4 additions & 0 deletions src/atomInterface/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ const shouldDisplayErrors = () => !getConfigOption('silenceErrors');

const isFormatOnSaveEnabled = () => getConfigOption('formatOnSaveOptions.enabled');

const isDisabledIfNotInPackageJson = () =>
getConfigOption('formatOnSaveOptions.isDisabledIfNotInPackageJson');

const shouldRespectEslintignore = () => getConfigOption('formatOnSaveOptions.respectEslintignore');

const getScopes = () => getConfigOption('formatOnSaveOptions.scopes');
Expand Down Expand Up @@ -75,6 +78,7 @@ module.exports = {
getPrettierOptions,
getScopes,
getWhitelistedGlobs,
isDisabledIfNotInPackageJson,
isFormatOnSaveEnabled,
isLinterEslintAutofixEnabled,
runLinter,
Expand Down
7 changes: 7 additions & 0 deletions src/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@
"type": "array",
"default": [],
"order": 6
},
"isDisabledIfNotInPackageJson": {
"title": "Only format if prettier is found in your project's dependencies",
"description": "Does not format on save if 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": 7
}
}
},
Expand Down
9 changes: 9 additions & 0 deletions src/editorInterface/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
// @flow
const _ = require('lodash/fp');
const path = require('path');

const EMBEDDED_SCOPES = ['text.html.vue', 'text.html.basic'];

const getBufferRange = (editor: TextEditor) => editor.getBuffer().getRange();
Expand All @@ -9,9 +12,15 @@ const isCurrentScopeEmbeddedScope = (editor: TextEditor) => EMBEDDED_SCOPES.incl

const getCurrentFilePath = (editor: TextEditor) => (editor.buffer.file ? editor.buffer.file.path : undefined);

const getCurrentDir: (editor: TextEditor) => ?string = _.flow(
getCurrentFilePath,
(maybeFilePath: ?string) => (typeof maybeFilePath === 'string' ? path.dirname(maybeFilePath) : undefined),
);

module.exports = {
getBufferRange,
isCurrentScopeEmbeddedScope,
getCurrentScope,
getCurrentFilePath,
getCurrentDir,
};
36 changes: 36 additions & 0 deletions src/formatOnSave/isPrettierInPackageJson.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// @flow
const _ = require('lodash/fp');
const readPgkUp = require('read-pkg-up');

const { getCurrentDir } = require('../editorInterface');
const { shouldUseEslint } = require('../atomInterface');

const hasPackageDependency = (packageName: string): ((packageJson: {}) => boolean) =>
_.flow(_.get('pkg.dependencies'), _.has(packageName));

const hasPackageDevDependency = (packageName: string) =>
_.flow(_.get('pkg.devDependencies'), _.has(packageName));

const hasPackage = (packageName: string): ((packageJson: {}) => boolean) =>
_.overSome([hasPackageDependency(packageName), hasPackageDevDependency(packageName)]);

const readContentsOfNearestPackageJson: TextEditor => {} = _.flow(
getCurrentDir,
_.set('cwd', _, {}),
readPgkUp.sync,
);

const isPrettierInPackageJson: (editor: TextEditor) => boolean = _.flow(
readContentsOfNearestPackageJson,
hasPackage('prettier'),
);

const isPrettierEslintInPackageJson: (editor: TextEditor) => boolean = _.flow(
readContentsOfNearestPackageJson,
_.overSome([hasPackage('prettier-eslint'), hasPackage('prettier-eslint-cli')]),
);

module.exports = _.cond([
[shouldUseEslint, isPrettierEslintInPackageJson],
[_.stubTrue, isPrettierInPackageJson],
]);
98 changes: 98 additions & 0 deletions src/formatOnSave/isPrettierInPackageJson.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
jest.mock('read-pkg-up');
jest.mock('../editorInterface');
jest.mock('../atomInterface');

const readPkgUp = require('read-pkg-up');
const { getCurrentDir } = require('../editorInterface');
const { shouldUseEslint } = require('../atomInterface');
const isPrettierInPackageJson = require('./isPrettierInPackageJson');

describe('when shouldUseEslint is false', () => {
beforeEach(() => {
shouldUseEslint.mockImplementation(() => false);
});

it('calls read-pkg-up with the current filepath', () => {
getCurrentDir.mockImplementation(() => '/parent-dir-of-file');

isPrettierInPackageJson();

expect(readPkgUp.sync).toHaveBeenCalledWith({ cwd: '/parent-dir-of-file' });
});

it('is true if prettier is a dependency', () => {
readPkgUp.sync.mockImplementation(() => ({ pkg: { dependencies: { prettier: '^0.0.1' } } }));

const actual = isPrettierInPackageJson();

expect(actual).toBe(true);
});

it('is true if prettier is a dev dependency', () => {
readPkgUp.sync.mockImplementation(() => ({ pkg: { devDependencies: { prettier: '^0.0.1' } } }));

const actual = isPrettierInPackageJson();

expect(actual).toBe(true);
});

it('is false if prettier is not a dependency', () => {
const actual = isPrettierInPackageJson();

expect(actual).toBe(false);
});
});

describe('when shouldUseEslint is true', () => {
beforeEach(() => {
shouldUseEslint.mockImplementation(() => true);
});

it('calls read-pkg-up with the current filepath', () => {
getCurrentDir.mockImplementation(() => '/parent-dir-of-file');

isPrettierInPackageJson();

expect(readPkgUp.sync).toHaveBeenCalledWith({ cwd: '/parent-dir-of-file' });
});

it('is true if prettier-eslint is a dependency', () => {
readPkgUp.sync.mockImplementation(() => ({ pkg: { dependencies: { 'prettier-eslint': '^0.0.1' } } }));

const actual = isPrettierInPackageJson();

expect(actual).toBe(true);
});

it('is true if prettier-eslint is a dev dependency', () => {
readPkgUp.sync.mockImplementation(() => ({ pkg: { devDependencies: { 'prettier-eslint': '^0.0.1' } } }));

const actual = isPrettierInPackageJson();

expect(actual).toBe(true);
});

it('is true if prettier-eslint-cli is a dependency', () => {
readPkgUp.sync.mockImplementation(() => ({ pkg: { dependencies: { 'prettier-eslint-cli': '^0.0.1' } } }));

const actual = isPrettierInPackageJson();

expect(actual).toBe(true);
});

it('is true if prettier-eslint-cli is a dev dependency', () => {
readPkgUp.sync.mockImplementation(() => ({
pkg: { devDependencies: { 'prettier-eslint-cli': '^0.0.1' } },
}));

const actual = isPrettierInPackageJson();

expect(actual).toBe(true);
});

it('is false if neither prettier-eslint nor prettier-eslint-cli are dependencies', () => {
const actual = isPrettierInPackageJson();

expect(actual).toBe(false);
});
});
3 changes: 3 additions & 0 deletions src/formatOnSave/shouldFormatOnSave.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ const {
getScopes,
getExcludedGlobs,
getWhitelistedGlobs,
isDisabledIfNotInPackageJson,
} = require('../atomInterface');
const isFilePathEslintignored = require('./isFilePathEslintIgnored');
const isPrettierInPackageJson = require('./isPrettierInPackageJson');

const hasFilePath = (editor: TextEditor) => !!getCurrentFilePath(editor);

Expand Down Expand Up @@ -42,6 +44,7 @@ const shouldFormatOnSave: (editor: TextEditor) => boolean = _.overEvery([
_.overEvery([noWhitelistGlobsPresent, filePathDoesNotMatchBlacklistGlobs]),
]),
isFilePathNotEslintignored,
_.overSome([_.negate(isDisabledIfNotInPackageJson), isPrettierInPackageJson]),
]);

module.exports = shouldFormatOnSave;
Loading

0 comments on commit 1a32d47

Please sign in to comment.