refactor: use ES6 fat arrows in application code (#522)

ES6 fat arrows provide reasonable `this` behaviour, which protects us
from some subtle accidental bugs, and erradicates `const self = this`
from the codebase.

Far arrows were not applied in Mocha code and AngularJS
controllers/services constructors since these frameworks rely on
`.bind()` on those functions.

Signed-off-by: Juan Cruz Viotti <jviottidc@gmail.com>
This commit is contained in:
Juan Cruz Viotti 2016-06-23 17:41:41 -04:00 committed by GitHub
parent 4d89b1b1f7
commit c44594b45e
40 changed files with 225 additions and 232 deletions

View File

@ -36,7 +36,7 @@ module.exports = yargs
.usage('Usage: $0 <image>')
.epilogue([
'Exit codes:',
_.map(EXIT_CODES, function(value, key) {
_.map(EXIT_CODES, (value, key) => {
const reason = _.map(_.split(key, '_'), _.capitalize).join(' ');
return ' ' + value + ' - ' + reason;
}).join('\n'),
@ -60,19 +60,19 @@ module.exports = yargs
.version(_.constant(packageJSON.version))
// Error reporting
.fail(function(message, error) {
.fail((message, error) => {
yargs.showHelp();
utils.printError(error || message);
process.exit(1);
})
// Assert that image exists
.check(function(argv) {
.check((argv) => {
fs.accessSync(argv._[0]);
return true;
})
.check(function(argv) {
.check((argv) => {
if (argv.robot && !argv.drive) {
throw new Error('Missing drive');
}
@ -80,7 +80,7 @@ module.exports = yargs
return true;
})
.check(function(argv) {
.check((argv) => {
if (argv.log && !argv.robot) {
throw new Error('The `--log` option requires `--robot`');
}
@ -139,7 +139,7 @@ module.exports = yargs
// We rely on the following heuristics to determine if the
// Etcher CLI is being run as a final packaged executable
// or by a tool passing the script as an argument:
.parse(_.attempt(function(argv) {
.parse(_.attempt((argv) => {
// Excluding the extension makes sure we cover cases
// like *.exe and *.cmd in Windows systems.

View File

@ -46,7 +46,7 @@ form.run([
yes: options.robot || options.yes || undefined
}
}).then(function(answers) {
}).then((answers) => {
if (!answers.yes) {
throw new Error('Aborted');
}
@ -61,7 +61,7 @@ form.run([
}, {
unmountOnSuccess: options.unmount,
validateWriteOnSuccess: options.check
}, function(state) {
}, (state) => {
if (options.robot) {
log.toStdout(JSON.stringify({
@ -78,7 +78,7 @@ form.run([
}
});
}).then(function(results) {
}).then((results) => {
if (options.robot) {
log.toStdout(JSON.stringify({
@ -103,7 +103,7 @@ form.run([
process.exit(EXIT_CODES.VALIDATION_ERROR);
}
}).catch(function(error) {
}).catch((error) => {
if (options.robot) {
log.toStderr(JSON.stringify({

View File

@ -50,7 +50,7 @@ const STDERR_STREAM = logStream || process.stderr;
* @example
* log.toStdout('Hello world!');
*/
exports.toStdout = function(line) {
exports.toStdout = (line) => {
STDOUT_STREAM.write(line + '\n');
};
@ -68,7 +68,7 @@ exports.toStdout = function(line) {
* @example
* log.toStderr('Hello world!');
*/
exports.toStderr = function(line) {
exports.toStderr = (line) => {
STDERR_STREAM.write(line + '\n');
};
@ -80,7 +80,7 @@ exports.toStderr = function(line) {
* @example
* log.close();
*/
exports.close = function() {
exports.close = () => {
if (logStream) {
logStream.close();
}

View File

@ -30,7 +30,7 @@ const chalk = require('chalk');
* @example
* utils.printError(new Error('Oops!'));
*/
exports.printError = function(error) {
exports.printError = (error) => {
if (_.isString(error)) {
error = new Error(error);
}

View File

@ -55,28 +55,28 @@ if (isWindows) {
* }, {
* unmountOnSuccess: true,
* validateWriteOnSuccess: true
* }, function(state) {
* }, (state) => {
* console.log(state.percentage);
* }).then(function() {
* }).then(() => {
* console.log('Done!');
* });
*/
exports.writeImage = function(imagePath, drive, options, onProgress) {
return umount.umountAsync(drive.device).then(function() {
exports.writeImage = (imagePath, drive, options, onProgress) => {
return umount.umountAsync(drive.device).then(() => {
return imageStream.getFromFilePath(imagePath);
}).then(function(image) {
}).then((image) => {
return imageWrite.write(drive.device, image.stream, {
check: options.validateWriteOnSuccess,
size: image.size,
transform: image.transform
});
}).then(function(writer) {
return new Bluebird(function(resolve, reject) {
}).then((writer) => {
return new Bluebird((resolve, reject) => {
writer.on('progress', onProgress);
writer.on('error', reject);
writer.on('done', resolve);
});
}).tap(function() {
}).tap(() => {
if (!options.unmountOnSuccess) {
return;
}

View File

@ -66,13 +66,13 @@ const app = angular.module('Etcher', [
require('./utils/byte-size/byte-size')
]);
app.run(function(AnalyticsService, UpdateNotifierService, SelectionStateModel) {
app.run((AnalyticsService, UpdateNotifierService, SelectionStateModel) => {
AnalyticsService.logEvent('Application start');
if (UpdateNotifierService.shouldCheckForUpdates()) {
AnalyticsService.logEvent('Checking for updates');
UpdateNotifierService.isLatestVersion().then(function(isLatestVersion) {
UpdateNotifierService.isLatestVersion().then((isLatestVersion) => {
// In case the internet connection is not good and checking the
// latest published version takes too long, only show notify
@ -89,7 +89,7 @@ app.run(function(AnalyticsService, UpdateNotifierService, SelectionStateModel) {
});
app.config(function($stateProvider, $urlRouterProvider) {
app.config(($stateProvider, $urlRouterProvider) => {
$urlRouterProvider.otherwise('/main');
$stateProvider
@ -118,7 +118,6 @@ app.controller('AppController', function(
OSNotificationService,
OSDialogService
) {
let self = this;
this.formats = SupportedFormatsModel;
this.selection = SelectionStateModel;
this.drives = DrivesModel;
@ -127,7 +126,7 @@ app.controller('AppController', function(
this.tooltipModal = TooltipModalService;
this.success = true;
this.handleError = function(error) {
this.handleError = (error) => {
OSDialogService.showError(error);
// Also throw it so it gets displayed in DevTools
@ -149,36 +148,36 @@ app.controller('AppController', function(
});
}
NotifierService.subscribe($scope, 'image-writer:state', function(state) {
NotifierService.subscribe($scope, 'image-writer:state', (state) => {
AnalyticsService.log(`Progress (${state.type}): ${state.progress}% at ${state.speed} MB/s (eta ${state.eta}s)`);
OSWindowProgressService.set(state.progress);
});
DriveScannerService.start();
DriveScannerService.on('error', self.handleError);
DriveScannerService.on('error', this.handleError);
DriveScannerService.on('drives', function(drives) {
self.drives.setDrives(drives);
DriveScannerService.on('drives', (drives) => {
this.drives.setDrives(drives);
if (_.isEmpty(drives)) {
DriveSelectorService.close();
}
});
this.selectImage = function(image) {
this.selectImage = (image) => {
if (!SupportedFormatsModel.isSupportedImage(image.path)) {
OSDialogService.showError('Invalid image', `${image.path} is not a supported image type.`);
AnalyticsService.logEvent('Invalid image', image);
return;
}
self.selection.setImage(image);
this.selection.setImage(image);
AnalyticsService.logEvent('Select image', image);
};
this.openImageSelector = function() {
return OSDialogService.selectImage().then(function(image) {
this.openImageSelector = () => {
return OSDialogService.selectImage().then((image) => {
// Avoid analytics and selection state changes
// if no file was resolved from the dialog.
@ -186,24 +185,24 @@ app.controller('AppController', function(
return;
}
self.selectImage(image);
this.selectImage(image);
});
};
this.selectDrive = function(drive) {
self.selection.setDrive(drive);
this.selectDrive = (drive) => {
this.selection.setDrive(drive);
AnalyticsService.logEvent('Select drive', {
device: drive.device
});
};
this.openDriveSelector = function() {
DriveSelectorService.open().then(self.selectDrive);
this.openDriveSelector = () => {
DriveSelectorService.open().then(this.selectDrive);
};
this.reselectImage = function() {
if (self.writer.isFlashing()) {
this.reselectImage = () => {
if (this.writer.isFlashing()) {
return;
}
@ -211,33 +210,33 @@ app.controller('AppController', function(
// de-selects the current drive, if any.
// This is made so the user effectively
// "returns" to the first step.
self.selection.clear();
this.selection.clear();
self.openImageSelector();
this.openImageSelector();
AnalyticsService.logEvent('Reselect image');
};
this.reselectDrive = function() {
if (self.writer.isFlashing()) {
this.reselectDrive = () => {
if (this.writer.isFlashing()) {
return;
}
self.openDriveSelector();
this.openDriveSelector();
AnalyticsService.logEvent('Reselect drive');
};
this.restartAfterFailure = function() {
self.selection.clear({
this.restartAfterFailure = () => {
this.selection.clear({
preserveImage: true
});
self.success = true;
this.success = true;
AnalyticsService.logEvent('Restart after failure');
};
this.flash = function(image, drive) {
this.flash = (image, drive) => {
if (self.writer.isFlashing()) {
if (this.writer.isFlashing()) {
return;
}
@ -250,7 +249,7 @@ app.controller('AppController', function(
device: drive.device
});
return self.writer.flash(image, drive).then(function(results) {
return this.writer.flash(image, drive).then((results) => {
if (results.cancelled) {
return;
@ -258,9 +257,9 @@ app.controller('AppController', function(
// TODO: Find a better way to manage flash/check
// success/error state than a global boolean flag.
self.success = results.passedValidation;
this.success = results.passedValidation;
if (self.success) {
if (this.success) {
OSNotificationService.send('Success!', 'Your flash is complete');
AnalyticsService.logEvent('Done');
$state.go('success', {
@ -271,7 +270,7 @@ app.controller('AppController', function(
AnalyticsService.logEvent('Validation error');
}
})
.catch(function(error) {
.catch((error) => {
if (error.type === 'check') {
AnalyticsService.logEvent('Validation error');
@ -279,7 +278,7 @@ app.controller('AppController', function(
AnalyticsService.logEvent('Flash error');
}
self.handleError(error);
this.handleError(error);
})
.finally(OSWindowProgressService.clear);
};

View File

@ -48,7 +48,7 @@ module.exports = function($uibModalInstance, DrivesModel, SelectionStateModel) {
* @example
* DriveSelectorController.closeModal();
*/
this.closeModal = function() {
this.closeModal = () => {
const selectedDrive = SelectionStateModel.getDrive();
// Sanity check to cover the case where a drive is selected,

View File

@ -29,11 +29,11 @@ module.exports = function($uibModal, $q) {
* @returns {Promise}
*
* @example
* DriveSelectorService.open().then(function(drive) {
* DriveSelectorService.open().then((drive) => {
* console.log(drive);
* });
*/
this.open = function() {
this.open = () => {
modal = $uibModal.open({
animation: true,
templateUrl: './components/drive-selector/templates/drive-selector-modal.tpl.html',
@ -55,7 +55,7 @@ module.exports = function($uibModal, $q) {
* @example
* DriveSelectorService.close();
*/
this.close = function() {
this.close = () => {
if (modal) {
return modal.dismiss();

View File

@ -30,7 +30,7 @@
* @example
* <progress-button percentage="{{ 40 }}" striped>My Progress Button</progress-button>
*/
module.exports = function() {
module.exports = () => {
return {
templateUrl: './components/progress-button/templates/progress-button.tpl.html',
restrict: 'E',

View File

@ -32,7 +32,7 @@ const fs = require('fs');
* @example
* <svg-icon path="path/to/icon.svg" width="40px" height="40px"></svg-icon>
*/
module.exports = function() {
module.exports = () => {
return {
templateUrl: './components/svg-icon/templates/svg-icon.tpl.html',
replace: true,
@ -42,7 +42,7 @@ module.exports = function() {
width: '@',
height: '@'
},
link: function(scope, element) {
link: (scope, element) => {
// This means the path to the icon should be
// relative to *this directory*.

View File

@ -33,7 +33,7 @@ module.exports = function($uibModalInstance, tooltipData) {
* @example
* TooltipModalController.closeModal();
*/
this.closeModal = function() {
this.closeModal = () => {
return $uibModalInstance.dismiss();
};

View File

@ -16,6 +16,8 @@
'use strict';
const _ = require('lodash');
module.exports = function($uibModal) {
/**
@ -34,16 +36,14 @@ module.exports = function($uibModal) {
* message: 'Tooltip contents'
* });
*/
this.show = function(options) {
this.show = (options) => {
return $uibModal.open({
animation: true,
templateUrl: './components/tooltip-modal/templates/tooltip-modal.tpl.html',
controller: 'TooltipModalController as modal',
size: 'tooltip-modal',
resolve: {
tooltipData: function() {
return options;
}
tooltipData: _.constant(options)
}
}).result;
};

View File

@ -40,7 +40,7 @@ module.exports = function($uibModalInstance, SettingsModel) {
* @example
* UpdateNotifierController.closeModal();
*/
this.closeModal = function() {
this.closeModal = () => {
return $uibModalInstance.dismiss();
};

View File

@ -36,20 +36,20 @@ module.exports = function($q, $http, UPDATE_NOTIFIER_URL) {
* @returns {Promise}
*
* @example
* UpdateNotifierS3Service.getLatestVersion().then(function(latestVersion) {
* UpdateNotifierS3Service.getLatestVersion().then((latestVersion) => {
* console.log('The latest version is: ' + latestVersion);
* });
*/
this.getLatestVersion = function() {
return $http.get(UPDATE_NOTIFIER_URL).then(function(response) {
return $q(function(resolve, reject) {
xml.parseString(response.data, function(error, result) {
this.getLatestVersion = () => {
return $http.get(UPDATE_NOTIFIER_URL).then((response) => {
return $q((resolve, reject) => {
xml.parseString(response.data, (error, result) => {
if (error) {
return reject(error);
}
const bucketEntries = result.ListBucketResult.Contents;
return resolve(_.reduce(bucketEntries, function(latest, entry) {
return resolve(_.reduce(bucketEntries, (latest, entry) => {
const version = _.chain(entry.Key)
.first()
.split('/')

View File

@ -29,14 +29,14 @@ module.exports = function($uibModal, UPDATE_NOTIFIER_SLEEP_TIME, ManifestBindSer
* @returns {Promise}
*
* @example
* UpdateNotifierService.isLatestVersion().then(function(isLatestVersion) {
* UpdateNotifierService.isLatestVersion().then((isLatestVersion) => {
* if (!isLatestVersion) {
* console.log('There is an update available');
* }
* });
*/
this.isLatestVersion = function() {
return UpdateNotifierS3Service.getLatestVersion().then(function(version) {
this.isLatestVersion = () => {
return UpdateNotifierS3Service.getLatestVersion().then((version) => {
return semver.gte(ManifestBindService.get('version'), version);
});
};
@ -53,7 +53,7 @@ module.exports = function($uibModal, UPDATE_NOTIFIER_SLEEP_TIME, ManifestBindSer
* console.log('We should check for updates!');
* }
*/
this.shouldCheckForUpdates = function() {
this.shouldCheckForUpdates = () => {
const lastUpdateNotify = SettingsModel.data.lastUpdateNotify;
if (!SettingsModel.data.sleepUpdateCheck || !lastUpdateNotify) {
@ -78,7 +78,7 @@ module.exports = function($uibModal, UPDATE_NOTIFIER_SLEEP_TIME, ManifestBindSer
* @example
* UpdateNotifierService.notify();
*/
this.notify = function() {
this.notify = () => {
return $uibModal.open({
animation: true,
templateUrl: './components/update-notifier/templates/update-notifier-modal.tpl.html',

View File

@ -22,7 +22,7 @@ let mainWindow = null;
electron.app.on('window-all-closed', electron.app.quit);
electron.app.on('ready', function() {
electron.app.on('ready', () => {
// No menu bar
electron.Menu.setApplicationMenu(null);
@ -40,17 +40,17 @@ electron.app.on('ready', function() {
// Prevent flash of white when starting the application
// https://github.com/atom/electron/issues/2172
mainWindow.webContents.on('did-finish-load', function() {
mainWindow.webContents.on('did-finish-load', () => {
// The flash of white is still present for a very short
// while after the WebView reports it finished loading
setTimeout(function() {
setTimeout(() => {
mainWindow.show();
}, 100);
});
mainWindow.on('closed', function() {
mainWindow.on('closed', () => {
mainWindow = null;
});
@ -62,22 +62,22 @@ electron.app.on('ready', function() {
// gains focus, and unregister them when the windows loses focus.
// See http://electron.atom.io/docs/api/global-shortcut/
mainWindow.on('focus', function() {
electron.globalShortcut.register('CmdOrCtrl+Alt+I', function() {
mainWindow.on('focus', () => {
electron.globalShortcut.register('CmdOrCtrl+Alt+I', () => {
mainWindow.webContents.openDevTools({
mode: 'undocked'
});
});
});
mainWindow.on('blur', function() {
mainWindow.on('blur', () => {
electron.globalShortcut.unregisterAll();
});
// Prevent external resources from being loaded (like images)
// when dropping them on the WebView.
// See https://github.com/electron/electron/issues/5919
mainWindow.webContents.on('will-navigate', function(event) {
mainWindow.webContents.on('will-navigate', (event) => {
event.preventDefault();
});

View File

@ -27,7 +27,6 @@ const MODULE_NAME = 'Etcher.Models.Drives';
const Drives = angular.module(MODULE_NAME, []);
Drives.service('DrivesModel', function() {
const self = this;
/**
* @summary Check if there are available drives
@ -41,8 +40,8 @@ Drives.service('DrivesModel', function() {
* console.log('There are available drives!');
* }
*/
this.hasAvailableDrives = function() {
return !_.isEmpty(self.getDrives());
this.hasAvailableDrives = () => {
return !_.isEmpty(this.getDrives());
};
/**
@ -58,7 +57,7 @@ Drives.service('DrivesModel', function() {
* @example
* DrivesModel.setDrives([ ... ]);
*/
this.setDrives = function(drives) {
this.setDrives = (drives) => {
Store.dispatch({
type: Store.Actions.SET_AVAILABLE_DRIVES,
data: drives
@ -73,10 +72,10 @@ Drives.service('DrivesModel', function() {
// The problem is that everytime you call `myImmutableObject.toJS()`
// you will get a new object, whose reference is different from
// the one you previously got, even if the data is exactly the same.
const memoizeImmutableListReference = function(func) {
const memoizeImmutableListReference = (func) => {
let previous = [];
return function() {
return () => {
const list = func.apply(this, arguments);
if (!_.isEqual(list, previous)) {
@ -97,7 +96,7 @@ Drives.service('DrivesModel', function() {
* @example
* const drives = DrivesModel.getDrives();
*/
this.getDrives = memoizeImmutableListReference(function() {
this.getDrives = memoizeImmutableListReference(() => {
return Store.getState().toJS().availableDrives;
});

View File

@ -27,7 +27,6 @@ const MODULE_NAME = 'Etcher.Models.SelectionState';
const SelectionStateModel = angular.module(MODULE_NAME, []);
SelectionStateModel.service('SelectionStateModel', function() {
let self = this;
/**
* @summary Set a drive
@ -43,7 +42,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
* size: 999999999
* });
*/
this.setDrive = function(drive) {
this.setDrive = (drive) => {
Store.dispatch({
type: Store.Actions.SELECT_DRIVE,
data: drive
@ -80,8 +79,8 @@ SelectionStateModel.service('SelectionStateModel', function() {
* console.log('We can flash the image to this drive!');
* }
*/
this.isDriveLargeEnough = function(drive) {
return (self.getImageSize() || 0) <= drive.size;
this.isDriveLargeEnough = (drive) => {
return (this.getImageSize() || 0) <= drive.size;
};
/**
@ -105,7 +104,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
* console.log('This drive is locked (e.g: write-protected)');
* }
*/
this.isDriveLocked = function(drive) {
this.isDriveLocked = (drive) => {
return _.get(drive, 'protected', false);
};
@ -133,10 +132,10 @@ SelectionStateModel.service('SelectionStateModel', function() {
* console.log('This drive is valid!');
* }
*/
this.isDriveValid = function(drive) {
this.isDriveValid = (drive) => {
return _.every([
self.isDriveLargeEnough(drive),
!self.isDriveLocked(drive)
this.isDriveLargeEnough(drive),
!this.isDriveLocked(drive)
]);
};
@ -152,11 +151,11 @@ SelectionStateModel.service('SelectionStateModel', function() {
* device: '/dev/disk2'
* });
*/
this.toggleSetDrive = function(drive) {
if (self.isCurrentDrive(drive)) {
self.removeDrive();
this.toggleSetDrive = (drive) => {
if (this.isCurrentDrive(drive)) {
this.removeDrive();
} else {
self.setDrive(drive);
this.setDrive(drive);
}
};
@ -172,7 +171,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
* path: 'foo.img'
* });
*/
this.setImage = function(image) {
this.setImage = (image) => {
Store.dispatch({
type: Store.Actions.SELECT_IMAGE,
data: image
@ -189,7 +188,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
* @example
* const drive = SelectionStateModel.getDrive();
*/
this.getDrive = function() {
this.getDrive = () => {
return _.get(Store.getState().toJS(), 'selection.drive');
};
@ -203,7 +202,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
* @example
* const imagePath = SelectionStateModel.getImagePath();
*/
this.getImagePath = function() {
this.getImagePath = () => {
return _.get(Store.getState().toJS(), 'selection.image.path');
};
@ -217,7 +216,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
* @example
* const imageSize = SelectionStateModel.getImageSize();
*/
this.getImageSize = function() {
this.getImageSize = () => {
return _.get(Store.getState().toJS(), 'selection.image.size');
};
@ -233,8 +232,8 @@ SelectionStateModel.service('SelectionStateModel', function() {
* console.log('There is a drive!');
* }
*/
this.hasDrive = function() {
return Boolean(self.getDrive());
this.hasDrive = () => {
return Boolean(this.getDrive());
};
/**
@ -249,8 +248,8 @@ SelectionStateModel.service('SelectionStateModel', function() {
* console.log('There is an image!');
* }
*/
this.hasImage = function() {
return Boolean(self.getImagePath() && self.getImageSize());
this.hasImage = () => {
return Boolean(this.getImagePath() && this.getImageSize());
};
/**
@ -261,7 +260,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
* @example
* SelectionStateModel.removeDrive();
*/
this.removeDrive = function() {
this.removeDrive = () => {
Store.dispatch({
type: Store.Actions.REMOVE_DRIVE
});
@ -275,7 +274,7 @@ SelectionStateModel.service('SelectionStateModel', function() {
* @example
* SelectionStateModel.removeImage();
*/
this.removeImage = function() {
this.removeImage = () => {
Store.dispatch({
type: Store.Actions.REMOVE_IMAGE
});
@ -295,7 +294,9 @@ SelectionStateModel.service('SelectionStateModel', function() {
* @example
* SelectionStateModel.clear({ preserveImage: true });
*/
this.clear = function(options = {}) {
this.clear = (options) => {
options = options || {};
if (!options.preserveImage) {
Store.dispatch({
type: Store.Actions.REMOVE_IMAGE
@ -327,12 +328,12 @@ SelectionStateModel.service('SelectionStateModel', function() {
* console.log('This is the current drive!');
* }
*/
this.isCurrentDrive = function(drive) {
this.isCurrentDrive = (drive) => {
if (!drive || !drive.device) {
return false;
}
return drive.device === _.get(self.getDrive(), 'device');
return drive.device === _.get(this.getDrive(), 'device');
};
});

View File

@ -51,11 +51,11 @@ const ACTIONS = _.fromPairs(_.map([
'SELECT_IMAGE',
'REMOVE_DRIVE',
'REMOVE_IMAGE'
], function(message) {
], (message) => {
return [ message, message ];
}));
const storeReducer = function(state, action) {
const storeReducer = (state, action) => {
state = state || DEFAULT_STATE;
switch (action.type) {

View File

@ -28,7 +28,6 @@ const MODULE_NAME = 'Etcher.Models.SupportedFormats';
const SupportedFormats = angular.module(MODULE_NAME, []);
SupportedFormats.service('SupportedFormatsModel', function() {
let self = this;
/**
* @summary Build an extension list getter from a type
@ -41,9 +40,9 @@ SupportedFormats.service('SupportedFormatsModel', function() {
* @example
* const extensions = getExtensionsFromTypeGetter('archive')();
*/
const getExtensionsFromTypeGetter = function(type) {
return function() {
return _.map(_.filter(imageStream.supportedFileTypes, function(fileType) {
const getExtensionsFromTypeGetter = (type) => {
return () => {
return _.map(_.filter(imageStream.supportedFileTypes, (fileType) => {
return fileType.type === type;
}), 'extension');
};
@ -56,7 +55,7 @@ SupportedFormats.service('SupportedFormatsModel', function() {
*
* @returns {String[]} compressed extensions
*
* SupportedFormatsModel.getCompressedExtensions().forEach(function(extension) {
* SupportedFormatsModel.getCompressedExtensions().forEach((extension) => {
* console.log('We support the ' + extension + ' compressed file format');
* });
*/
@ -69,7 +68,7 @@ SupportedFormats.service('SupportedFormatsModel', function() {
*
* @returns {String[]} no compressed extensions
*
* SupportedFormatsModel.getNonCompressedExtensions().forEach(function(extension) {
* SupportedFormatsModel.getNonCompressedExtensions().forEach((extension) => {
* console.log('We support the ' + extension + ' file format');
* });
*/
@ -82,7 +81,7 @@ SupportedFormats.service('SupportedFormatsModel', function() {
*
* @returns {String[]} archive extensions
*
* SupportedFormatsModel.getArchiveExtensions().forEach(function(extension) {
* SupportedFormatsModel.getArchiveExtensions().forEach((extension) => {
* console.log('We support the ' + extension + ' file format');
* });
*/
@ -95,11 +94,11 @@ SupportedFormats.service('SupportedFormatsModel', function() {
*
* @returns {String[]} extensions
*
* SupportedFormatsModel.getAllExtensions().forEach(function(extension) {
* SupportedFormatsModel.getAllExtensions().forEach((extension) => {
* console.log('We support the ' + extension + ' format');
* });
*/
this.getAllExtensions = function() {
this.getAllExtensions = () => {
return _.map(imageStream.supportedFileTypes, 'extension');
};
@ -115,21 +114,21 @@ SupportedFormats.service('SupportedFormatsModel', function() {
* console.log('The image is supported!');
* }
*/
this.isSupportedImage = function(image) {
this.isSupportedImage = (image) => {
const extension = path.extname(image).slice(1);
if (_.some([
_.includes(self.getNonCompressedExtensions(), extension),
_.includes(self.getArchiveExtensions(), extension)
_.includes(this.getNonCompressedExtensions(), extension),
_.includes(this.getArchiveExtensions(), extension)
])) {
return true;
}
if (!_.includes(self.getCompressedExtensions(), extension)) {
if (!_.includes(this.getCompressedExtensions(), extension)) {
return false;
}
return self.isSupportedImage(path.basename(image, `.${extension}`));
return this.isSupportedImage(path.basename(image, `.${extension}`));
};
});

View File

@ -38,7 +38,7 @@ const analytics = angular.module(MODULE_NAME, [
require('../models/settings')
]);
analytics.config(function($mixpanelProvider) {
analytics.config(($mixpanelProvider) => {
$mixpanelProvider.apiKey('63e5fc4563e00928da67d1226364dd4c');
$mixpanelProvider.superProperties({
@ -59,7 +59,7 @@ analytics.config(function($mixpanelProvider) {
// TrackJS integration
// http://docs.trackjs.com/tracker/framework-integrations
analytics.run(function($window) {
analytics.run(($window) => {
// Don't configure TrackJS when
// running inside the test suite
@ -73,9 +73,9 @@ analytics.run(function($window) {
});
});
analytics.config(function($provide) {
$provide.decorator('$exceptionHandler', function($delegate, $window, $injector) {
return function(exception, cause) {
analytics.config(($provide) => {
$provide.decorator('$exceptionHandler', ($delegate, $window, $injector) => {
return (exception, cause) => {
const SettingsModel = $injector.get('SettingsModel');
if (SettingsModel.data.errorReporting) {
@ -86,12 +86,12 @@ analytics.config(function($provide) {
};
});
$provide.decorator('$log', function($delegate, $window, $injector) {
$provide.decorator('$log', ($delegate, $window, $injector) => {
// Save the original $log.debug()
let debugFn = $delegate.debug;
$delegate.debug = function(message) {
$delegate.debug = (message) => {
message = new Date() + ' ' + message;
const SettingsModel = $injector.get('SettingsModel');
@ -108,7 +108,6 @@ analytics.config(function($provide) {
});
analytics.service('AnalyticsService', function($log, $mixpanel, SettingsModel) {
let self = this;
/**
* @summary Log a debug message
@ -123,7 +122,7 @@ analytics.service('AnalyticsService', function($log, $mixpanel, SettingsModel) {
* @example
* AnalyticsService.log('Hello World');
*/
this.log = function(message) {
this.log = (message) => {
$log.debug(message);
};
@ -143,7 +142,7 @@ analytics.service('AnalyticsService', function($log, $mixpanel, SettingsModel) {
* image: '/dev/disk2'
* });
*/
this.logEvent = function(message, data) {
this.logEvent = (message, data) => {
if (SettingsModel.data.errorReporting) {
@ -158,7 +157,7 @@ analytics.service('AnalyticsService', function($log, $mixpanel, SettingsModel) {
message += ` (${JSON.stringify(data)})`;
}
self.log(message);
this.log(message);
};
});

View File

@ -29,7 +29,7 @@ const drivelist = require('drivelist');
const MODULE_NAME = 'Etcher.Modules.DriveScanner';
const driveScanner = angular.module(MODULE_NAME, []);
driveScanner.factory('DriveScannerService', function() {
driveScanner.factory('DriveScannerService', () => {
const DRIVE_SCANNER_INTERVAL_MS = 2000;
const emitter = new EventEmitter();

View File

@ -31,7 +31,6 @@ const imageWriter = angular.module(MODULE_NAME, [
]);
imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel, NotifierService) {
let self = this;
/**
* @summary Reset flash state
@ -41,7 +40,7 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel,
* @example
* ImageWriterService.resetState();
*/
this.resetState = function() {
this.resetState = () => {
Store.dispatch({
type: Store.Actions.RESET_FLASH_STATE
});
@ -57,11 +56,11 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel,
speed: 0
};
Store.subscribe(function() {
Store.subscribe(() => {
// Safely bring the state to the world of Angular
$timeout(function() {
self.state = Store.getState().toJS().flashState;
$timeout(() => {
this.state = Store.getState().toJS().flashState;
});
});
@ -78,7 +77,7 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel,
* console.log('We\'re currently flashing');
* }
*/
this.isFlashing = function() {
this.isFlashing = () => {
return Store.getState().toJS().isFlashing;
};
@ -95,7 +94,7 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel,
* @example
* ImageWriterService.setFlashing(true);
*/
this.setFlashing = function(status) {
this.setFlashing = (status) => {
if (Boolean(status)) {
Store.dispatch({
type: Store.Actions.SET_FLASHING_FLAG
@ -125,7 +124,7 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel,
* speed: 100000000000
* });
*/
this.setProgressState = function(state) {
this.setProgressState = (state) => {
Store.dispatch({
type: Store.Actions.SET_FLASH_STATE,
data: {
@ -138,7 +137,7 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel,
}
});
NotifierService.emit('image-writer:state', self.state);
NotifierService.emit('image-writer:state', this.state);
};
/**
@ -159,12 +158,12 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel,
* @example
* ImageWriter.performWrite('path/to/image.img', {
* device: '/dev/disk2'
* }, function(state) {
* }, (state) => {
* console.log(state.percentage);
* });
*/
this.performWrite = function(image, drive, onProgress) {
return $q(function(resolve, reject) {
this.performWrite = (image, drive, onProgress) => {
return $q((resolve, reject) => {
const child = childWriter.write(image, drive, SettingsModel.data);
child.on('error', reject);
child.on('done', resolve);
@ -189,19 +188,19 @@ imageWriter.service('ImageWriterService', function($q, $timeout, SettingsModel,
* @example
* ImageWriterService.flash('foo.img', {
* device: '/dev/disk2'
* }).then(function() {
* }).then(() => {
* console.log('Write completed!');
* });
*/
this.flash = function(image, drive) {
if (self.isFlashing()) {
this.flash = (image, drive) => {
if (this.isFlashing()) {
return $q.reject(new Error('There is already a flash in progress'));
}
self.setFlashing(true);
this.setFlashing(true);
return self.performWrite(image, drive, self.setProgressState).finally(function() {
self.setFlashing(false);
return this.performWrite(image, drive, this.setProgressState).finally(() => {
this.setFlashing(false);
});
};

View File

@ -34,12 +34,12 @@ module.exports = function($q, SupportedFormatsModel) {
* @returns {Promise};
*
* @example
* OSDialogService.selectImage().then(function(image) {
* OSDialogService.selectImage().then((image) => {
* console.log('The selected image is', image.path);
* });
*/
this.selectImage = function() {
return $q(function(resolve, reject) {
this.selectImage = () => {
return $q((resolve, reject) => {
electron.remote.dialog.showOpenDialog({
properties: [
'openFile'
@ -50,7 +50,7 @@ module.exports = function($q, SupportedFormatsModel) {
extensions: SupportedFormatsModel.getAllExtensions()
}
]
}, function(files) {
}, (files) => {
// `_.first` is smart enough to not throw and return `undefined`
// if we pass it an `undefined` value (e.g: when the selection
@ -61,7 +61,7 @@ module.exports = function($q, SupportedFormatsModel) {
return resolve();
}
fs.stat(imagePath, function(error, stats) {
fs.stat(imagePath, (error, stats) => {
if (error) {
return reject(error);
@ -93,12 +93,12 @@ module.exports = function($q, SupportedFormatsModel) {
* @example
* OSDialogService.showError('Foo Bar', 'An error happened!');
*/
this.showError = function(error, description) {
this.showError = (error, description) => {
error = error || {};
// Try to get as most information as possible about the error
// rather than falling back to generic messages right away.
const title = _.attempt(function() {
const title = _.attempt(() => {
if (_.isString(error)) {
return error;
}

View File

@ -34,13 +34,13 @@ const fs = require('fs');
* @example
* <div os-dropzone="doSomething($file)">Drag a file here</div>
*/
module.exports = function($timeout) {
module.exports = ($timeout) => {
return {
restrict: 'A',
scope: {
osDropzone: '&'
},
link: function(scope, element) {
link: (scope, element) => {
const domElement = element[0];
// See https://github.com/electron/electron/blob/master/docs/api/file-object.md
@ -50,12 +50,12 @@ module.exports = function($timeout) {
domElement.ondragleave = _.constant(false);
domElement.ondragend = _.constant(false);
domElement.ondrop = function(event) {
domElement.ondrop = (event) => {
event.preventDefault();
const filename = event.dataTransfer.files[0].path;
// Safely bring this to the word of Angular
$timeout(function() {
$timeout(() => {
scope.osDropzone({
// Pass the filename as a named

View File

@ -36,11 +36,11 @@ module.exports = function() {
*
* @example
* const notification = OSNotificationService.send('Hello', 'Foo Bar Bar');
* notification.onclick = function() {
* notification.onclick = () => {
* console.log('The notification has been clicked');
* };
*/
this.send = function(title, body) {
this.send = (title, body) => {
// `app.dock` is only defined in OS X
if (electron.remote.app.dock) {

View File

@ -32,17 +32,17 @@ const electron = require('electron');
* @example
* <button os-open-external="https://resin.io">Resin.io</button>
*/
module.exports = function() {
module.exports = () => {
return {
restrict: 'A',
scope: false,
link: function(scope, element, attributes) {
link: (scope, element, attributes) => {
// This directive might be added to elements
// other than buttons.
element.css('cursor', 'pointer');
element.on('click', function() {
element.on('click', () => {
electron.shell.openExternal(attributes.osOpenExternal);
});
}

View File

@ -19,7 +19,6 @@
const electron = require('electron');
module.exports = function() {
const self = this;
/**
* @summary A reference to the current renderer Electron window
@ -47,12 +46,12 @@ module.exports = function() {
* @example
* OSWindowProgressService.set(85);
*/
this.set = function(percentage) {
this.set = (percentage) => {
if (percentage > 100 || percentage < 0) {
throw new Error(`Invalid window progress percentage: ${percentage}`);
}
self.currentWindow.setProgressBar(percentage / 100);
this.currentWindow.setProgressBar(percentage / 100);
};
/**
@ -63,10 +62,10 @@ module.exports = function() {
* @example
* OSWindowProgressService.clear();
*/
this.clear = function() {
this.clear = () => {
// Passing 0 or null/undefined doesn't work.
self.currentWindow.setProgressBar(-1);
this.currentWindow.setProgressBar(-1);
};

View File

@ -43,7 +43,7 @@ module.exports = function($state, $stateParams, SelectionStateModel, AnalyticsSe
* @example
* FinishController.restart({ preserveImage: true });
*/
this.restart = function(options) {
this.restart = (options) => {
SelectionStateModel.clear(options);
AnalyticsService.logEvent('Restart', options);
$state.go('main');

View File

@ -37,7 +37,7 @@ const FinishPage = angular.module(MODULE_NAME, [
FinishPage.controller('FinishController', require('./controllers/finish'));
FinishPage.config(function($stateProvider) {
FinishPage.config(($stateProvider) => {
$stateProvider
.state('success', {
url: '/success/:checksum',

View File

@ -29,7 +29,7 @@ const SettingsPage = angular.module(MODULE_NAME, [
SettingsPage.controller('SettingsController', require('./controllers/settings'));
SettingsPage.config(function($stateProvider) {
SettingsPage.config(($stateProvider) => {
$stateProvider
.state('settings', {
url: '/settings',

View File

@ -16,7 +16,7 @@
'use strict';
module.exports = function() {
module.exports = () => {
/**
* @summary Convert bytes to gigabytes
@ -29,7 +29,7 @@ module.exports = function() {
* @example
* {{ 7801405440 | gigabytes }}
*/
return function(bytes) {
return (bytes) => {
return bytes / 1000000000;
};

View File

@ -31,11 +31,11 @@
* @example
* <span manifest-bind="version"></button>
*/
module.exports = function(ManifestBindService) {
module.exports = (ManifestBindService) => {
return {
restrict: 'A',
scope: false,
link: function(scope, element, attributes) {
link: (scope, element, attributes) => {
const value = ManifestBindService.get(attributes.manifestBind);
if (!value) {

View File

@ -32,7 +32,7 @@ module.exports = function() {
* @example
* const version = ManifestBindService.get('version');
*/
this.get = function(attribute) {
this.get = (attribute) => {
return _.get(packageJSON, attribute);
};

View File

@ -37,12 +37,12 @@ module.exports = function($rootScope) {
* @param {Function} callback - callback
*
* @example
* NotifierService.subscribe($scope, 'my-event', function() {
* NotifierService.subscribe($scope, 'my-event', () => {
* console.log('Event received!');
* });
*/
this.subscribe = function(scope, name, callback) {
const handler = $rootScope.$on(name, function(event, data) {
this.subscribe = (scope, name, callback) => {
const handler = $rootScope.$on(name, (event, data) => {
return callback(data);
});
@ -60,7 +60,7 @@ module.exports = function($rootScope) {
* @example
* NotifierService.emit('my-event', 'Foo');
*/
this.emit = function(name, data) {
this.emit = (name, data) => {
$rootScope.$emit(name, data);
};

View File

@ -18,7 +18,7 @@
const path = require('path');
module.exports = function() {
module.exports = () => {
/**
* @summary Get the basename of a path
@ -31,7 +31,7 @@ module.exports = function() {
* @example
* {{ '/foo/bar/baz' | basename }}
*/
return function(input) {
return (input) => {
if (!input) {
return;
}

View File

@ -41,24 +41,24 @@ const EXIT_CODES = require('../exit-codes');
* unmountOnSuccess: true
* });
*
* child.on('progress', function(state) {
* child.on('progress', (state) => {
* console.log(state);
* });
*
* child.on('error', function(error) {
* child.on('error', (error) => {
* throw error;
* });
*
* child.on('done', function(results) {
* child.on('done', (results) => {
* if (results.passedValidation) {
* console.log('Validation was successful!');
* }
* });
*/
exports.write = function(image, drive, options) {
exports.write = (image, drive, options) => {
const emitter = new EventEmitter();
utils.getTemporaryLogFilePath().then(function(logFile) {
utils.getTemporaryLogFilePath().then((logFile) => {
const argv = utils.getCLIWriterArguments({
entryPoint: rendererUtils.getApplicationEntryPoint(),
logFile: logFile,
@ -77,19 +77,19 @@ exports.write = function(image, drive, options) {
env: process.env
});
child.stderr.on('data', function(data) {
child.stderr.on('data', (data) => {
emitter.emit('error', new Error(data.toString()));
});
child.on('message', function(message) {
child.on('message', (message) => {
emitter.emit(message.command, message.data);
});
child.on('error', function(error) {
child.on('error', (error) => {
emitter.emit('error', error);
});
child.on('close', function(code) {
child.on('close', (code) => {
if (code === EXIT_CODES.CANCELLED) {
return emitter.emit('done', {
cancelled: true

View File

@ -35,7 +35,7 @@ const CONSTANTS = require('./constants');
* @example
* const entryPoint = rendererUtils.getApplicationEntryPoint();
*/
exports.getApplicationEntryPoint = function() {
exports.getApplicationEntryPoint = () => {
if (isRunningInAsar()) {
return path.join(process.resourcesPath, 'app.asar');
}

View File

@ -44,7 +44,7 @@ const packageJSON = require('../../../package.json');
* console.log(utils.getBooleanArgumentForm('check', false));
* > '--no-check'
*/
exports.getBooleanArgumentForm = function(argumentName, value) {
exports.getBooleanArgumentForm = (argumentName, value) => {
const prefix = value ? '--' : '--no-';
return prefix + argumentName;
};
@ -72,7 +72,7 @@ exports.getBooleanArgumentForm = function(argumentName, value) {
* unmountOnSuccess: true
* });
*/
exports.getCLIWriterArguments = function(options) {
exports.getCLIWriterArguments = (options) => {
const argv = [
options.entryPoint,
options.image,
@ -110,8 +110,8 @@ exports.getCLIWriterArguments = function(options) {
* @example
* const escapedArguments = utils.escapeWhiteSpacesFromArguments(process.argv);
*/
exports.escapeWhiteSpacesFromArguments = function(argv) {
return _.map(argv, function(argument) {
exports.escapeWhiteSpacesFromArguments = (argv) => {
return _.map(argv, (argument) => {
return argument.replace(/\s/g, '\\ ');
});
};
@ -125,15 +125,13 @@ exports.escapeWhiteSpacesFromArguments = function(argv) {
* @returns {Promise}
*
* @example
* utils.getTemporaryLogFilePath().then(function(filePath) {
* utils.getTemporaryLogFilePath().then((filePath) => {
* console.log(filePath);
* });
*/
exports.getTemporaryLogFilePath = function() {
exports.getTemporaryLogFilePath = () => {
return tmp.fileAsync({
prefix: `${packageJSON.name}-`,
postfix: '.log'
}).then(function(logFilePath) {
return logFilePath;
});
};

View File

@ -42,7 +42,7 @@ const utils = require('./utils');
const EXECUTABLE = process.argv[0];
const ETCHER_ARGUMENTS = process.argv.slice(2);
return isElevated().then(function(elevated) {
return isElevated().then((elevated) => {
const logFile = process.env[CONSTANTS.TEMPORARY_LOG_FILE_ENVIRONMENT_VARIABLE];
if (process.send) {
@ -51,7 +51,7 @@ return isElevated().then(function(elevated) {
// the stream that function returns gets closed
// when it initially reaches EOF, instead of waiting
// for the file to receive more data.
const tail = _.attempt(function() {
const tail = _.attempt(() => {
if (os.platform() === 'win32') {
@ -66,12 +66,12 @@ return isElevated().then(function(elevated) {
return new Tail(logFile);
});
tail.on('error', function(error) {
tail.on('error', (error) => {
console.error(error);
process.exit(1);
});
tail.on('line', function(line) {
tail.on('line', (line) => {
process.send(JSON.parse(line));
});
}
@ -99,12 +99,12 @@ return isElevated().then(function(elevated) {
waitForTermination: true
}).catch({
code: 'ELEVATE_CANCELLED'
}, function() {
}, () => {
process.exit(EXIT_CODES.CANCELLED);
});
}
const command = _.attempt(function() {
const command = _.attempt(() => {
const commandPrefix = [
// Some elevation tools, like `pkexec` or `kdesudo`, don't
@ -155,7 +155,7 @@ return isElevated().then(function(elevated) {
// Translate the current arguments to
// point to the new mount location.
.concat(_.map(process.argv, function(argv) {
.concat(_.map(process.argv, (argv) => {
return argv.replace(process.env.APPDIR, mountPoint);
}))
@ -180,25 +180,25 @@ return isElevated().then(function(elevated) {
return sudoPrompt.execAsync(command, {
name: packageJSON.displayName
}).then(function(stdout, stderr) {
}).then((stdout, stderr) => {
if (!_.isEmpty(stderr)) {
throw new Error(stderr);
}
}).catch({
message: 'User did not grant permission.'
}, function() {
}, () => {
process.exit(EXIT_CODES.CANCELLED);
});
}
return new Bluebird(function(resolve, reject) {
return new Bluebird((resolve, reject) => {
const child = childProcess.spawn(EXECUTABLE, ETCHER_ARGUMENTS);
child.on('error', reject);
child.on('close', resolve);
}).then(function(exitCode) {
}).then((exitCode) => {
process.exit(exitCode);
});
}).catch(function(error) {
}).catch((error) => {
console.error(error);
process.exit(EXIT_CODES.GENERAL_ERROR);
});