chore: add ESLint Lodash plugin (#1148)

This is one step towards enforcing the linter until we barely have to
check for style issues on code reviews.

Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
This commit is contained in:
Juan Cruz Viotti 2017-03-08 19:11:15 -04:00 committed by GitHub
parent 6c8bc117ab
commit df8611df11
18 changed files with 192 additions and 52 deletions

View File

@ -4,6 +4,8 @@ env:
es6: true es6: true
node: true node: true
mocha: true mocha: true
plugins:
- lodash
extends: 'eslint:recommended' extends: 'eslint:recommended'
rules: rules:
@ -571,3 +573,75 @@ rules:
- error - error
- before: true - before: true
after: false after: false
# Lodash
lodash/chain-style:
- error
- explicit
lodash/identity-shorthand:
- error
- always
lodash/import-scope:
- error
- full
lodash/matches-prop-shorthand:
- error
- always
lodash/matches-shorthand:
- error
- always
lodash/no-commit:
- error
lodash/path-style:
- error
- array
lodash/prefer-compact:
- error
lodash/prefer-filter:
- error
- 5
lodash/prefer-flat-map:
- error
lodash/prefer-invoke-map:
- error
lodash/prefer-map:
- error
lodash/prefer-reject:
- error
lodash/prefer-thru:
- error
lodash/prefer-wrapper-method:
- error
lodash/prop-shorthand:
- error
- always
lodash/prefer-constant:
- error
- true
- true
lodash/prefer-get:
- error
- 2
lodash/prefer-includes:
- error
- includeNative: true
lodash/prefer-is-nil:
- error
lodash/prefer-lodash-chain:
- error
lodash/prefer-lodash-method:
- error
lodash/prefer-lodash-typecheck:
- error
lodash/prefer-matches:
- error
- 3
lodash/prefer-noop:
- error
lodash/prefer-over-quantifier:
- error
lodash/prefer-startswith:
- error
lodash/prefer-times:
- error

View File

@ -127,9 +127,10 @@ return isElevated().then((elevated) => {
// Translate the current arguments to point to the AppImage // Translate the current arguments to point to the AppImage
// Relative paths are resolved from `/tmp/.mount_XXXXXX/usr` // Relative paths are resolved from `/tmp/.mount_XXXXXX/usr`
const translatedArguments = _.map(_.tail(process.argv), (argv) => { const translatedArguments = _.chain(process.argv)
return argv.replace(path.join(process.env.APPDIR, 'usr/'), ''); .tail()
}); .invokeMap('replace', path.join(process.env.APPDIR, 'usr/'), '')
.value();
return commandPrefix return commandPrefix
.concat([ process.env.APPIMAGE ]) .concat([ process.env.APPIMAGE ])

View File

@ -43,18 +43,14 @@ exports.HUMAN_FRIENDLY = {
* @memberof HUMAN_FRIENDLY * @memberof HUMAN_FRIENDLY
* @returns {String} message * @returns {String} message
*/ */
EPERM: () => { EPERM: _.constant('You\'re not authorized to perform this operation'),
return 'You\'re not authorized to perform this operation';
},
/** /**
* @property {Function} EACCES * @property {Function} EACCES
* @memberof HUMAN_FRIENDLY * @memberof HUMAN_FRIENDLY
* @returns {String} message * @returns {String} message
*/ */
EACCES: () => { EACCES: _.constant('You don\'t have access to this resource')
return 'You\'re don\'t have access to this resource';
}
/* eslint-enable new-cap */ /* eslint-enable new-cap */

View File

@ -189,7 +189,7 @@ FlashState.service('FlashStateModel', function() {
* } * }
*/ */
this.wasLastFlashCancelled = () => { this.wasLastFlashCancelled = () => {
return _.get(this.getFlashResults(), 'cancelled', false); return _.get(this.getFlashResults(), [ 'cancelled' ], false);
}; };
/** /**

View File

@ -111,7 +111,7 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
* const image = SelectionStateModel.getImage(); * const image = SelectionStateModel.getImage();
*/ */
this.getImage = () => { this.getImage = () => {
return _.get(Store.getState().toJS(), 'selection.image'); return _.get(Store.getState().toJS(), [ 'selection', 'image' ]);
}; };
/** /**
@ -125,7 +125,11 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
* const imagePath = SelectionStateModel.getImagePath(); * const imagePath = SelectionStateModel.getImagePath();
*/ */
this.getImagePath = () => { this.getImagePath = () => {
return _.get(Store.getState().toJS(), 'selection.image.path'); return _.get(Store.getState().toJS(), [
'selection',
'image',
'path'
]);
}; };
/** /**
@ -139,7 +143,11 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
* const imageSize = SelectionStateModel.getImageSize(); * const imageSize = SelectionStateModel.getImageSize();
*/ */
this.getImageSize = () => { this.getImageSize = () => {
return _.get(Store.getState().toJS(), 'selection.image.size'); return _.get(Store.getState().toJS(), [
'selection',
'image',
'size'
]);
}; };
/** /**
@ -153,7 +161,11 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
* const imageUrl = SelectionStateModel.getImageUrl(); * const imageUrl = SelectionStateModel.getImageUrl();
*/ */
this.getImageUrl = () => { this.getImageUrl = () => {
return _.get(Store.getState().toJS(), 'selection.image.url'); return _.get(Store.getState().toJS(), [
'selection',
'image',
'url'
]);
}; };
/** /**
@ -167,7 +179,11 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
* const imageName = SelectionStateModel.getImageName(); * const imageName = SelectionStateModel.getImageName();
*/ */
this.getImageName = () => { this.getImageName = () => {
return _.get(Store.getState().toJS(), 'selection.image.name'); return _.get(Store.getState().toJS(), [
'selection',
'image',
'name'
]);
}; };
/** /**
@ -181,7 +197,11 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
* const imageLogo = SelectionStateModel.getImageLogo(); * const imageLogo = SelectionStateModel.getImageLogo();
*/ */
this.getImageLogo = () => { this.getImageLogo = () => {
return _.get(Store.getState().toJS(), 'selection.image.logo'); return _.get(Store.getState().toJS(), [
'selection',
'image',
'logo'
]);
}; };
/** /**
@ -195,7 +215,11 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
* const imageSupportUrl = SelectionStateModel.getImageSupportUrl(); * const imageSupportUrl = SelectionStateModel.getImageSupportUrl();
*/ */
this.getImageSupportUrl = () => { this.getImageSupportUrl = () => {
return _.get(Store.getState().toJS(), 'selection.image.supportUrl'); return _.get(Store.getState().toJS(), [
'selection',
'image',
'supportUrl'
]);
}; };
/** /**
@ -209,7 +233,11 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
* const imageRecommendedDriveSize = SelectionStateModel.getImageRecommendedDriveSize(); * const imageRecommendedDriveSize = SelectionStateModel.getImageRecommendedDriveSize();
*/ */
this.getImageRecommendedDriveSize = () => { this.getImageRecommendedDriveSize = () => {
return _.get(Store.getState().toJS(), 'selection.image.recommendedDriveSize'); return _.get(Store.getState().toJS(), [
'selection',
'image',
'recommendedDriveSize'
]);
}; };
/** /**
@ -316,7 +344,7 @@ SelectionStateModel.service('SelectionStateModel', function(DrivesModel) {
return false; return false;
} }
return drive === _.get(this.getDrive(), 'device'); return drive === _.get(this.getDrive(), [ 'device' ]);
}; };
}); });

View File

@ -75,6 +75,30 @@ const ACTIONS = _.fromPairs(_.map([
return [ message, message ]; return [ message, message ];
})); }));
/**
* @summary Find a drive from the list of available drives
* @function
* @private
*
* @param {Object} state - application state
* @param {String} device - drive device
* @returns {(Object|Undefined)} drive
*
* @example
* const drive = findDrive(state, '/dev/disk2');
*/
const findDrive = (state, device) => {
/* eslint-disable lodash/prefer-lodash-method */
return state.get('availableDrives').find((drive) => {
return drive.get('device') === device;
});
/* eslint-enable lodash/prefer-lodash-method */
};
/** /**
* @summary The redux store reducer * @summary The redux store reducer
* @function * @function
@ -156,7 +180,7 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
throw new Error(`Invalid state type: ${action.data.type}`); throw new Error(`Invalid state type: ${action.data.type}`);
} }
if (_.isUndefined(action.data.percentage) || _.isNull(action.data.percentage)) { if (_.isNil(action.data.percentage)) {
throw new Error('Missing state percentage'); throw new Error('Missing state percentage');
} }
@ -172,7 +196,7 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
throw new Error(`Invalid state eta: ${action.data.eta}`); throw new Error(`Invalid state eta: ${action.data.eta}`);
} }
if (_.isUndefined(action.data.speed) || _.isNull(action.data.speed)) { if (_.isNil(action.data.speed)) {
throw new Error('Missing state speed'); throw new Error('Missing state speed');
} }
@ -231,9 +255,7 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
throw new Error(`Invalid drive: ${action.data}`); throw new Error(`Invalid drive: ${action.data}`);
} }
const selectedDrive = state.get('availableDrives').find((drive) => { const selectedDrive = findDrive(state, action.data);
return drive.get('device') === action.data;
});
if (!selectedDrive) { if (!selectedDrive) {
throw new Error(`The drive is not available: ${action.data}`); throw new Error(`The drive is not available: ${action.data}`);
@ -280,10 +302,7 @@ const storeReducer = (state = DEFAULT_STATE, action) => {
throw new Error(`Invalid image logo: ${action.data.logo}`); throw new Error(`Invalid image logo: ${action.data.logo}`);
} }
const selectedDevice = state.getIn([ 'selection', 'drive' ]); const selectedDrive = findDrive(state, state.getIn([ 'selection', 'drive' ]));
const selectedDrive = state.get('availableDrives').find((drive) => {
return drive.get('device') === selectedDevice;
});
return _.attempt(() => { return _.attempt(() => {
if (selectedDrive && !_.every([ if (selectedDrive && !_.every([

View File

@ -42,8 +42,8 @@ SupportedFormats.service('SupportedFormatsModel', function() {
*/ */
const getExtensionsFromTypeGetter = (type) => { const getExtensionsFromTypeGetter = (type) => {
return () => { return () => {
return _.map(_.filter(imageStream.supportedFileTypes, (fileType) => { return _.map(_.filter(imageStream.supportedFileTypes, {
return fileType.type === type; type
}), 'extension'); }), 'extension');
}; };
}; };

View File

@ -159,7 +159,7 @@ analytics.service('AnalyticsService', function($log, $window, $mixpanel, Setting
* } * }
*/ */
this.shouldReportError = (error) => { this.shouldReportError = (error) => {
return !_.has(error, 'report') || Boolean(error.report); return !_.has(error, [ 'report' ]) || Boolean(error.report);
}; };
/** /**

View File

@ -37,10 +37,15 @@ driveScanner.factory('DriveScannerService', (SettingsModel) => {
const DRIVE_SCANNER_FIRST_SCAN_DELAY_MS = 0; const DRIVE_SCANNER_FIRST_SCAN_DELAY_MS = 0;
const emitter = new EventEmitter(); const emitter = new EventEmitter();
/* eslint-disable lodash/prefer-lodash-method */
const availableDrives = Rx.Observable.timer( const availableDrives = Rx.Observable.timer(
DRIVE_SCANNER_FIRST_SCAN_DELAY_MS, DRIVE_SCANNER_FIRST_SCAN_DELAY_MS,
DRIVE_SCANNER_INTERVAL_MS DRIVE_SCANNER_INTERVAL_MS
) )
/* eslint-enable lodash/prefer-lodash-method */
.flatMap(() => { .flatMap(() => {
return Rx.Observable.fromNodeCallback(drivelist.list)(); return Rx.Observable.fromNodeCallback(drivelist.list)();
}) })
@ -63,8 +68,8 @@ driveScanner.factory('DriveScannerService', (SettingsModel) => {
return drives; return drives;
} }
return _.reject(drives, (drive) => { return _.reject(drives, {
return drive.system; system: true
}); });
}) })
.pausable(new Rx.Subject()); .pausable(new Rx.Subject());

View File

@ -26,6 +26,11 @@
const angular = require('angular'); const angular = require('angular');
const MODULE_NAME = 'Etcher.Utils.ByteSize'; const MODULE_NAME = 'Etcher.Utils.ByteSize';
const ByteSize = angular.module(MODULE_NAME, []); const ByteSize = angular.module(MODULE_NAME, []);
/* eslint-disable lodash/prefer-lodash-method */
ByteSize.filter('gigabyte', require('./filters/gigabyte')); ByteSize.filter('gigabyte', require('./filters/gigabyte'));
/* eslint-enable lodash/prefer-lodash-method */
module.exports = MODULE_NAME; module.exports = MODULE_NAME;

View File

@ -26,6 +26,11 @@
const angular = require('angular'); const angular = require('angular');
const MODULE_NAME = 'Etcher.Utils.Path'; const MODULE_NAME = 'Etcher.Utils.Path';
const Path = angular.module(MODULE_NAME, []); const Path = angular.module(MODULE_NAME, []);
/* eslint-disable lodash/prefer-lodash-method */
Path.filter('basename', require('./filters/basename')); Path.filter('basename', require('./filters/basename'));
/* eslint-enable lodash/prefer-lodash-method */
module.exports = MODULE_NAME; module.exports = MODULE_NAME;

View File

@ -51,8 +51,8 @@ exports.getEntries = (archive) => {
const EMPTY_ENTRY_SIZE = 0; const EMPTY_ENTRY_SIZE = 0;
return resolve(_.chain(zip.entries()) return resolve(_.chain(zip.entries())
.omitBy((entry) => { .omitBy({
return entry.size === EMPTY_ENTRY_SIZE; size: EMPTY_ENTRY_SIZE
}) })
.map((metadata) => { .map((metadata) => {
return { return {

View File

@ -39,5 +39,5 @@ exports.getArchiveMimeType = (file) => {
const MAGIC_NUMBER_BUFFER_END = 261; const MAGIC_NUMBER_BUFFER_END = 261;
const chunk = readChunk.sync(file, MAGIC_NUMBER_BUFFER_START, MAGIC_NUMBER_BUFFER_END); const chunk = readChunk.sync(file, MAGIC_NUMBER_BUFFER_START, MAGIC_NUMBER_BUFFER_END);
return _.get(archiveType(chunk), 'mime', 'application/octet-stream'); return _.get(archiveType(chunk), [ 'mime' ], 'application/octet-stream');
}; };

View File

@ -49,7 +49,7 @@ const UNKNOWN_SIZE = 0;
* } * }
*/ */
exports.isDriveLocked = (drive) => { exports.isDriveLocked = (drive) => {
return Boolean(_.get(drive, 'protected', false)); return Boolean(_.get(drive, [ 'protected' ], false));
}; };
/** /**
@ -71,7 +71,7 @@ exports.isDriveLocked = (drive) => {
* } * }
*/ */
exports.isSystemDrive = (drive) => { exports.isSystemDrive = (drive) => {
return Boolean(_.get(drive, 'system', false)); return Boolean(_.get(drive, [ 'system' ], false));
}; };
/** /**
@ -108,8 +108,8 @@ exports.isSystemDrive = (drive) => {
* } * }
*/ */
exports.isSourceDrive = (drive, image) => { exports.isSourceDrive = (drive, image) => {
const mountpoints = _.get(drive, 'mountpoints', []); const mountpoints = _.get(drive, [ 'mountpoints' ], []);
const imagePath = _.get(image, 'path'); const imagePath = _.get(image, [ 'path' ]);
if (!imagePath || _.isEmpty(mountpoints)) { if (!imagePath || _.isEmpty(mountpoints)) {
return false; return false;
@ -142,7 +142,7 @@ exports.isSourceDrive = (drive, image) => {
* } * }
*/ */
exports.isDriveLargeEnough = (drive, image) => { exports.isDriveLargeEnough = (drive, image) => {
return _.get(drive, 'size', UNKNOWN_SIZE) >= _.get(image, 'size', UNKNOWN_SIZE); return _.get(drive, [ 'size' ], UNKNOWN_SIZE) >= _.get(image, [ 'size' ], UNKNOWN_SIZE);
}; };
/** /**
@ -206,5 +206,5 @@ exports.isDriveValid = (drive, image) => {
* } * }
*/ */
exports.isDriveSizeRecommended = (drive, image) => { exports.isDriveSizeRecommended = (drive, image) => {
return _.get(drive, 'size', UNKNOWN_SIZE) >= _.get(image, 'recommendedDriveSize', UNKNOWN_SIZE); return _.get(drive, [ 'size' ], UNKNOWN_SIZE) >= _.get(image, [ 'recommendedDriveSize' ], UNKNOWN_SIZE);
}; };

View File

@ -32,7 +32,7 @@ const _ = require('lodash');
* } * }
*/ */
exports.isEnabled = (environment) => { exports.isEnabled = (environment) => {
const value = _.get(environment, 'ETCHER_CLI_ROBOT', false); const value = _.get(environment, [ 'ETCHER_CLI_ROBOT' ], false);
return Boolean(value === 'false' ? false : value); return Boolean(value === 'false' ? false : value);
}; };
@ -177,7 +177,7 @@ exports.recomposeErrorMessage = (message) => {
* > 'foo' * > 'foo'
*/ */
exports.getCommand = (message) => { exports.getCommand = (message) => {
return _.get(message, 'command'); return _.get(message, [ 'command' ]);
}; };
/** /**
@ -200,7 +200,7 @@ exports.getCommand = (message) => {
* > { foo: 1 } * > { foo: 1 }
*/ */
exports.getData = (message) => { exports.getData = (message) => {
return _.get(message, 'data', {}); return _.get(message, [ 'data' ], {});
}; };
/** /**

View File

@ -112,6 +112,7 @@
"electron-packager": "^7.0.1", "electron-packager": "^7.0.1",
"electron-prebuilt": "1.4.4", "electron-prebuilt": "1.4.4",
"eslint": "^3.16.1", "eslint": "^3.16.1",
"eslint-plugin-lodash": "^2.3.5",
"file-exists": "^1.0.0", "file-exists": "^1.0.0",
"html-angular-validate": "^0.1.9", "html-angular-validate": "^0.1.9",
"jsonfile": "^2.3.1", "jsonfile": "^2.3.1",

View File

@ -90,7 +90,7 @@ describe('CLI: Errors', function() {
it('should provide a friendly message for EACCES', function() { it('should provide a friendly message for EACCES', function() {
const error = new Error('foo bar'); const error = new Error('foo bar');
error.code = 'EACCES'; error.code = 'EACCES';
const message = 'EACCES: You\'re don\'t have access to this resource'; const message = 'EACCES: You don\'t have access to this resource';
m.chai.expect(errors.getErrorMessage(error)).to.equal(message); m.chai.expect(errors.getErrorMessage(error)).to.equal(message);
}); });

View File

@ -16,6 +16,8 @@
'use strict'; 'use strict';
const _ = require('lodash');
module.exports = { module.exports = {
subjectParser: 'angular', subjectParser: 'angular',
@ -40,16 +42,20 @@ module.exports = {
}, },
transformTemplateData: (data) => { transformTemplateData: (data) => {
data.features = data.commits.filter((commit) => { data.features = _.filter(data.commits, {
return commit.subject.type === 'feat'; subject: {
type: 'feat'
}
}); });
data.fixes = data.commits.filter((commit) => { data.fixes = _.filter(data.commits, {
return commit.subject.type === 'fix'; subject: {
type: 'fix'
}
}); });
data.misc = data.commits.filter((commit) => { data.misc = _.filter(data.commits, (commit) => {
return ![ 'fix', 'feat' ].includes(commit.subject.type); return !_.includes([ 'fix', 'feat' ], commit.subject.type);
}); });
return data; return data;