Upgrade prettier to 1.10, fix linter issues

This commit is contained in:
Ben Gotow 2018-01-24 14:13:08 -08:00
parent d2de477023
commit 22357dff60
63 changed files with 263 additions and 411 deletions

View file

@ -42,8 +42,6 @@ let thirdPartyClasses = {
};
module.exports = function(grunt) {
let { cp, mkdir, rm } = grunt.config('taskHelpers');
let relativePathForClass = classname => classname + '.html';
let outputPathFor = function(relativePath) {
@ -51,14 +49,8 @@ module.exports = function(grunt) {
return path.join(classDocsOutputDir, relativePath);
};
var processFields = function(json, fields, tasks) {
var processFields = function(json, fields = [], tasks = []) {
let val;
if (fields == null) {
fields = [];
}
if (tasks == null) {
tasks = [];
}
if (json instanceof Array) {
return (() => {
let result = [];
@ -90,7 +82,7 @@ module.exports = function(grunt) {
};
return grunt.registerTask('docs-render', 'Builds html from the API docs', function() {
let documentation, filename, html, match, meta, name, result, section, val;
let documentation, match, name, result, section, val;
let classDocsOutputDir = grunt.config.get('classDocsOutputDir');
// Parse API reference Markdown

View file

@ -1,19 +1,16 @@
const React = require("react");
const AccountSidebar = require("./components/account-sidebar");
const {ComponentRegistry, WorkspaceStore} = require("mailspring-exports");
const AccountSidebar = require('./components/account-sidebar');
const { ComponentRegistry, WorkspaceStore } = require('mailspring-exports');
module.exports = {
item: null, // The DOM item the main React component renders into
activate(state) {
this.state = state;
ComponentRegistry.register(AccountSidebar,
{location: WorkspaceStore.Location.RootSidebar});
ComponentRegistry.register(AccountSidebar, { location: WorkspaceStore.Location.RootSidebar });
},
deactivate(state) {
this.state = state;
ComponentRegistry.unregister(AccountSidebar);
}
},
};

View file

@ -5,10 +5,7 @@
*/
const Reflux = require('reflux');
const Actions = [
'focusAccounts',
'setKeyCollapsed',
];
const Actions = ['focusAccounts', 'setKeyCollapsed'];
for (let idx of Array.from(Actions)) {
Actions[idx] = Reflux.createAction(Actions[idx]);

View file

@ -96,15 +96,14 @@ const onEditItem = function(item, value) {
};
class SidebarItem {
static forPerspective(id, perspective, opts) {
let counterStyle, left;
if (opts == null) {
opts = {};
}
static forPerspective(id, perspective, opts = {}) {
let counterStyle;
if (perspective.isInbox()) {
counterStyle = OutlineViewItem.CounterStyles.Alt;
}
const collapsed = isItemCollapsed(id);
return Object.assign(
{
id,
@ -115,7 +114,7 @@ class SidebarItem {
children: [],
perspective,
selected: isItemSelected(perspective),
collapsed: (left = isItemCollapsed(id)) != null ? left : true,
collapsed: collapsed != null ? collapsed : true,
counterStyle,
onDelete: opts.deletable ? onDeleteItem : undefined,
onEdited: opts.editable ? onEditItem : undefined,
@ -160,13 +159,7 @@ class SidebarItem {
);
}
static forCategories(categories, opts) {
if (categories == null) {
categories = [];
}
if (opts == null) {
opts = {};
}
static forCategories(categories = [], opts = {}) {
const id = idForCategories(categories);
const contextMenuLabel = _str.capitalize(
categories[0] != null ? categories[0].displayType() : undefined
@ -183,10 +176,7 @@ class SidebarItem {
return this.forPerspective(id, perspective, opts);
}
static forStarred(accountIds, opts) {
if (opts == null) {
opts = {};
}
static forStarred(accountIds, opts = {}) {
const perspective = MailboxPerspective.forStarred(accountIds);
let id = 'Starred';
if (opts.name) {
@ -195,10 +185,7 @@ class SidebarItem {
return this.forPerspective(id, perspective, opts);
}
static forUnread(accountIds, opts) {
if (opts == null) {
opts = {};
}
static forUnread(accountIds, opts = {}) {
let categories = accountIds.map(accId => {
return CategoryStore.getCategoryByRole(accId, 'inbox');
});
@ -218,10 +205,7 @@ class SidebarItem {
return this.forPerspective(id, perspective, opts);
}
static forDrafts(accountIds, opts) {
if (opts == null) {
opts = {};
}
static forDrafts(accountIds, opts = {}) {
const perspective = MailboxPerspective.forDrafts(accountIds);
const id = `Drafts-${opts.name}`;
return this.forPerspective(id, perspective, opts);

View file

@ -173,12 +173,8 @@ class SidebarSection {
};
}
static forUserCategories(account, param) {
static forUserCategories(account, { title, collapsible } = {}) {
let onCollapseToggled;
if (param == null) {
param = {};
}
let { title, collapsible } = param;
if (!account) {
return;
}

View file

@ -152,9 +152,9 @@ class ActivityEventStore extends MailspringStore {
threadId: message.threadId,
data: {
title: 'New open',
subtitle: `${recipient
? recipient.displayName()
: 'Someone'} just opened ${message.subject}`,
subtitle: `${recipient ? recipient.displayName() : 'Someone'} just opened ${
message.subject
}`,
canReply: false,
tag: 'message-open',
onActivate: () => {
@ -192,9 +192,9 @@ class ActivityEventStore extends MailspringStore {
threadId: message.threadId,
data: {
title: 'New click',
subtitle: `${recipient
? recipient.displayName()
: 'Someone'} just clicked ${link.url}.`,
subtitle: `${recipient ? recipient.displayName() : 'Someone'} just clicked ${
link.url
}.`,
canReply: false,
tag: 'link-open',
onActivate: () => {

View file

@ -12,10 +12,7 @@ const ActivityListEmptyState = function ActivityListEmptyState() {
<div className="text">
Enable read receipts{' '}
<RetinaImg name="icon-activity-mailopen.png" mode={RetinaImg.Mode.ContentDark} /> or link
tracking <RetinaImg
name="icon-activity-linkopen.png"
mode={RetinaImg.Mode.ContentDark}
/>{' '}
tracking <RetinaImg name="icon-activity-linkopen.png" mode={RetinaImg.Mode.ContentDark} />{' '}
to see notifications here.
</div>
</div>

View file

@ -4,10 +4,7 @@ const LabelPicker = require('./label-picker');
const { ComponentRegistry } = require('mailspring-exports');
module.exports = {
activate(state) {
if (state == null) {
state = {};
}
activate(state = {}) {
this.state = state;
ComponentRegistry.register(MovePicker, { role: 'ThreadActionsToolbarButton' });
ComponentRegistry.register(LabelPicker, { role: 'ThreadActionsToolbarButton' });

View file

@ -32,7 +32,9 @@ export function applySignature(body, signature) {
if (signature) {
const contentBefore = newBody.slice(0, insertionPoint);
const contentAfter = newBody.slice(insertionPoint);
return `${contentBefore}${additionalWhitespace}<signature id="${signature.id}">${signature.body}</signature>${contentAfter}`;
return `${contentBefore}${additionalWhitespace}<signature id="${signature.id}">${
signature.body
}</signature>${contentAfter}`;
} else {
return newBody;
}

View file

@ -38,7 +38,9 @@ describe('SignatureComposerExtension', function signatureComposerExtension() {
SignatureComposerExtension.prepareNewDraft({ draft: a });
expect(a.body).toEqual(
`This is a test! <br/><signature id="1">${TEST_SIGNATURE.body}</signature><div class="gmail_quote">Hello world</div>`
`This is a test! <br/><signature id="1">${
TEST_SIGNATURE.body
}</signature><div class="gmail_quote">Hello world</div>`
);
SignatureComposerExtension.prepareNewDraft({ draft: b });
expect(b.body).toEqual(
@ -50,7 +52,9 @@ describe('SignatureComposerExtension', function signatureComposerExtension() {
{
name: 'With blockquote',
body: `This is a test! <signature id="x"><div>SIG</div></signature><div class="gmail_quote">Hello world</div>`,
expected: `This is a test! <signature id="1">${TEST_SIGNATURE.body}</signature><div class="gmail_quote">Hello world</div>`,
expected: `This is a test! <signature id="1">${
TEST_SIGNATURE.body
}</signature><div class="gmail_quote">Hello world</div>`,
},
{
name: 'Populated signature div',
@ -70,7 +74,9 @@ describe('SignatureComposerExtension', function signatureComposerExtension() {
];
scenarios.forEach(scenario => {
it(`should replace the signature if a signature is already present (${scenario.name})`, () => {
it(`should replace the signature if a signature is already present (${
scenario.name
})`, () => {
const message = new Message({
draft: true,
from: ['one@nylas.com'],

View file

@ -72,8 +72,9 @@ class TemplateStore extends MailspringStore {
if (err) {
AppEnv.showErrorDialog({
title: 'Cannot scan templates directory',
message: `Mailspring was unable to read the contents of your templates directory (${this
._templatesDir}). You may want to delete this folder or ensure filesystem permissions are set correctly.`,
message: `Mailspring was unable to read the contents of your templates directory (${
this._templatesDir
}). You may want to delete this folder or ensure filesystem permissions are set correctly.`,
});
return;
}

View file

@ -1,4 +1,3 @@
import _ from 'underscore';
import React from 'react';
import { Utils } from 'mailspring-exports';
import { InjectedComponentSet, ListTabular } from 'mailspring-component-kit';

View file

@ -24,7 +24,9 @@ export default class LinkTrackingButton extends React.Component {
) {
return `Link tracking does not work offline. Please re-enable when you come back online.`;
}
return `Unfortunately, link tracking servers are currently not available. Please try again later. Error: ${error.message}`;
return `Unfortunately, link tracking servers are currently not available. Please try again later. Error: ${
error.message
}`;
}
render() {

View file

@ -52,7 +52,9 @@ export default class LinkTrackingComposerExtension extends ComposerExtension {
return;
}
const encoded = encodeURIComponent(url);
const redirectUrl = `${PLUGIN_URL}/link/${draft.headerMessageId}/${links.length}?redirect=${encoded}`;
const redirectUrl = `${PLUGIN_URL}/link/${draft.headerMessageId}/${
links.length
}?redirect=${encoded}`;
links.push({
url,

View file

@ -34,9 +34,9 @@ export default class LinkTrackingMessageExtension extends MessageViewExtension {
dotNode.style =
'margin-bottom: 0.75em; margin-left: 1px; margin-right: 1px; vertical-align: text-bottom; width: 6px;';
if (links[nodeHref].click_count > 0) {
dotNode.title = `${links[nodeHref].click_count} click${links[nodeHref].click_count === 1
? ''
: 's'} (${originalHref})`;
dotNode.title = `${links[nodeHref].click_count} click${
links[nodeHref].click_count === 1 ? '' : 's'
} (${originalHref})`;
dotNode.src = 'mailspring://link-tracking/assets/ic-tracking-visited@2x.png';
dotNode.style =
'margin-bottom: 0.75em; margin-left: 1px; margin-right: 1px; vertical-align: text-bottom; width: 6px; cursor: pointer;';

View file

@ -1,7 +1,7 @@
const React = require('react');
const ReactDOM = require('react-dom');
const ReactTestUtils = require('react-dom/test-utils');
const { Contact, Message } = require('mailspring-exports');
const { Message } = require('mailspring-exports');
const MessageParticipants = require('../lib/message-participants').default;
const user_1 = {
@ -25,10 +25,6 @@ const user_5 = {
email: 'user5@nylas.com',
};
const many_users = __range__(0, 100, true).map(
i => new Contact({ name: `User ${i}`, email: `${i}@app.com` })
);
const test_message = new Message().fromJSON({
id: '111',
from: [user_1],
@ -136,13 +132,3 @@ describe('MessageParticipants', function() {
// )
// # this should be false because we don't count bccs
// expect(p2._isToEveryone()).toBe false
function __range__(left, right, inclusive) {
let range = [];
let ascending = left < right;
let end = !inclusive ? right : ascending ? right + 1 : right - 1;
for (let i = left; ascending ? i < end : i > end; ascending ? i++ : i--) {
range.push(i);
}
return range;
}

View file

@ -48,9 +48,9 @@ export default class UpdateNotification extends React.Component {
return (
<Notification
priority="4"
title={`An update to Mailspring is available ${version
? `(${version.replace('Mailspring', '').trim()})`
: ''}`}
title={`An update to Mailspring is available ${
version ? `(${version.replace('Mailspring', '').trim()})` : ''
}`}
subtitle="View changelog"
subtitleAction={this._onViewChangelog}
icon="volstead-upgrade.png"

View file

@ -33,29 +33,29 @@ export default class SyncActivity extends React.Component {
}
render() {
let accountComponents = Object.entries(
this.props.syncState
).map(([accountId, accountSyncState]) => {
const account = AccountStore.accountForId(accountId);
if (!account) {
return false;
let accountComponents = Object.entries(this.props.syncState).map(
([accountId, accountSyncState]) => {
const account = AccountStore.accountForId(accountId);
if (!account) {
return false;
}
let folderComponents = Object.entries(accountSyncState).map(([folderPath, folderState]) => {
return this.renderFolderProgress(folderPath, folderState);
});
if (folderComponents.length === 0) {
folderComponents = <div>Gathering folders...</div>;
}
return (
<div className="account" key={accountId}>
<h2>{account.emailAddress}</h2>
{folderComponents}
</div>
);
}
let folderComponents = Object.entries(accountSyncState).map(([folderPath, folderState]) => {
return this.renderFolderProgress(folderPath, folderState);
});
if (folderComponents.length === 0) {
folderComponents = <div>Gathering folders...</div>;
}
return (
<div className="account" key={accountId}>
<h2>{account.emailAddress}</h2>
{folderComponents}
</div>
);
});
);
if (accountComponents.length === 0) {
accountComponents = (

View file

@ -115,9 +115,9 @@ export default class TutorialPage extends React.Component {
<div
key={step.id}
id={step.id}
className={`overlay ${seen.includes(step) ? 'seen' : ''} ${current === step
? 'expanded'
: ''}`}
className={`overlay ${seen.includes(step) ? 'seen' : ''} ${
current === step ? 'expanded' : ''
}`}
style={{ left: `${step.xDot}%`, top: `${step.yDot}%` }}
onMouseOver={this._onMouseOverOverlay}
>

View file

@ -24,7 +24,9 @@ export default class OpenTrackingButton extends React.Component {
) {
return `Open tracking does not work offline. Please re-enable when you come back online.`;
}
return `Unfortunately, open tracking is currently not available. Please try again later. Error: ${error.message}`;
return `Unfortunately, open tracking is currently not available. Please try again later. Error: ${
error.message
}`;
}
render() {

View file

@ -70,14 +70,13 @@ class ConfigSchemaItem extends React.Component {
<div className="item">
<label htmlFor={this.props.keyPath}>{this.props.configSchema.title}:</label>
<select onChange={this._onChangeValue} value={this.props.config.get(this.props.keyPath)}>
{_.zip(
this.props.configSchema.enum,
this.props.configSchema.enumLabels
).map(([value, label]) => (
<option key={value} value={value}>
{label}
</option>
))}
{_.zip(this.props.configSchema.enum, this.props.configSchema.enumLabels).map(
([value, label]) => (
<option key={value} value={value}>
{label}
</option>
)
)}
</select>
{note}
</div>

View file

@ -196,9 +196,7 @@ class PreferencesIdentity extends React.Component {
<div className="row padded">
<div>
Thank you for using{' '}
<strong
style={{ textTransform: 'capitalize' }}
>{`Mailspring ${planDisplayName}`}</strong>{' '}
<strong style={{ textTransform: 'capitalize' }}>{`Mailspring ${planDisplayName}`}</strong>{' '}
and supporting independent software. Get the most out of your subscription: visit the{' '}
<a href="https://foundry376.zendesk.com/hc/en-us/sections/115000521592-Getting-Started">
Help Center

View file

@ -46,7 +46,8 @@ class DefaultMailClientItem extends React.Component {
style={{ marginBottom: 12 }}
className="btn btn-small"
onClick={() =>
shell.openExternal('https://foundry376.zendesk.com/hc/en-us/articles/115002281851')}
shell.openExternal('https://foundry376.zendesk.com/hc/en-us/articles/115002281851')
}
>
Use Mailspring as default mail client
</div>

View file

@ -40,7 +40,9 @@ function assertMetadataShape(value) {
}
if (t.lastReplyTimestamp && !(t.lastReplyTimestamp < Date.now() / 100)) {
throw new Error(
`"lastReplyTimestamp" should always be a unix timestamp in seconds. Received ${t.lastReplyTimestamp}`
`"lastReplyTimestamp" should always be a unix timestamp in seconds. Received ${
t.lastReplyTimestamp
}`
);
}
delete t.expiration;

View file

@ -6,18 +6,16 @@ import ThreadListStore from './thread-list-store';
import InjectsToolbarButtons, { ToolbarRole } from './injects-toolbar-buttons';
function getObservable() {
return Rx.Observable
.combineLatest(
Rx.Observable.fromStore(FocusedContentStore),
ThreadListStore.selectionObservable(),
(store, items) => ({ focusedThread: store.focused('thread'), items })
)
.map(({ focusedThread, items }) => {
if (focusedThread) {
return [focusedThread];
}
return items;
});
return Rx.Observable.combineLatest(
Rx.Observable.fromStore(FocusedContentStore),
ThreadListStore.selectionObservable(),
(store, items) => ({ focusedThread: store.focused('thread'), items })
).map(({ focusedThread, items }) => {
if (focusedThread) {
return [focusedThread];
}
return items;
});
}
const MessageListToolbar = ({ items, injectedButtons }) => {

View file

@ -50,7 +50,7 @@ class ThreadListStore extends MailspringStore {
this.createListDataSource();
};
_onDataChanged = param => {
_onDataChanged = ({ previous, next } = {}) => {
// This code keeps the focus and keyboard cursor in sync with the thread list.
// When the thread list changes, it looks to see if the focused thread is gone,
// or no longer matches the query criteria and advances the focus to the next
@ -58,11 +58,6 @@ class ThreadListStore extends MailspringStore {
// This means that removing a thread from view in any way causes selection
// to advance to the adjacent thread. Nice and declarative.
if (param == null) {
param = {};
}
const { previous, next } = param;
if (previous && next) {
const focused = FocusedContentStore.focused('thread');
const keyboard = FocusedContentStore.keyboardCursor('thread');

View file

@ -160,7 +160,6 @@ class ThreadList extends React.Component {
}
_threadPropsProvider(item) {
let left;
let classes = classnames({
unread: item.unread,
});
@ -206,8 +205,7 @@ class ThreadList extends React.Component {
callback(true);
};
const disabledPackages =
(left = AppEnv.config.get('core.disabledPackages')) != null ? left : [];
const disabledPackages = AppEnv.config.get('core.disabledPackages') || [];
if (disabledPackages.includes('thread-snooze')) {
return props;
}
@ -235,14 +233,13 @@ class ThreadList extends React.Component {
}
_targetItemsForMouseEvent(event) {
let needle;
const itemThreadId = this.refs.list.itemIdAtPoint(event.clientX, event.clientY);
if (!itemThreadId) {
return null;
}
const dataSource = ThreadListStore.dataSource();
if (((needle = itemThreadId), dataSource.selection.ids().includes(needle))) {
if (itemThreadId && dataSource.selection.ids().includes(itemThreadId)) {
return {
threadIds: dataSource.selection.ids(),
accountIds: _.uniq(_.pluck(dataSource.selection.items(), 'accountId')),
@ -327,9 +324,7 @@ class ThreadList extends React.Component {
};
_onSnoozeItem = () => {
let left;
const disabledPackages =
(left = AppEnv.config.get('core.disabledPackages')) != null ? left : [];
const disabledPackages = AppEnv.config.get('core.disabledPackages') || [];
if (disabledPackages.includes('thread-snooze')) {
return;
}

View file

@ -73,7 +73,8 @@ class ThreadSearchBar extends Component {
suggestions={suggestions}
isSearching={isSearching}
suggestionKey={suggestion =>
suggestion.label || (suggestion.contact || {}).id || (suggestion.thread || {}).id}
suggestion.label || (suggestion.contact || {}).id || (suggestion.thread || {}).id
}
suggestionRenderer={this._renderSuggestion}
onSelectSuggestion={this._onSelectSuggestion}
onSubmitSearchQuery={this._onSubmitSearchQuery}

View file

@ -186,37 +186,36 @@ export class Notifier {
// TODO: Use xGMLabels + folder on message to identify which ones
// are in the inbox to avoid needing threads here.
return DatabaseStore.findAll(
Thread,
Thread.attributes.id.in(Object.keys(threadIds))
).then(threadsArray => {
const threads = {};
for (const t of threadsArray) {
threads[t.id] = t;
}
// Filter new messages to just the ones in the inbox
const newMessagesInInbox = newMessages.filter(({ threadId }) => {
return threads[threadId] && threads[threadId].categories.find(c => c.role === 'inbox');
});
if (newMessagesInInbox.length === 0) {
return;
}
for (const msg of newMessagesInInbox) {
this.unnotifiedQueue.push({ message: msg, thread: threads[msg.threadId] });
}
if (!this.hasScheduledNotify) {
if (AppEnv.config.get('core.notifications.sounds')) {
this._playNewMailSound =
this._playNewMailSound ||
_.debounce(() => SoundRegistry.playSound('new-mail'), 5000, true);
this._playNewMailSound();
return DatabaseStore.findAll(Thread, Thread.attributes.id.in(Object.keys(threadIds))).then(
threadsArray => {
const threads = {};
for (const t of threadsArray) {
threads[t.id] = t;
}
// Filter new messages to just the ones in the inbox
const newMessagesInInbox = newMessages.filter(({ threadId }) => {
return threads[threadId] && threads[threadId].categories.find(c => c.role === 'inbox');
});
if (newMessagesInInbox.length === 0) {
return;
}
for (const msg of newMessagesInInbox) {
this.unnotifiedQueue.push({ message: msg, thread: threads[msg.threadId] });
}
if (!this.hasScheduledNotify) {
if (AppEnv.config.get('core.notifications.sounds')) {
this._playNewMailSound =
this._playNewMailSound ||
_.debounce(() => SoundRegistry.playSound('new-mail'), 5000, true);
this._playNewMailSound();
}
this._notifyMessages();
}
this._notifyMessages();
}
});
);
}
}

View file

@ -8,10 +8,7 @@ describe('QuotedHTMLTransformer', function() {
return fs.readFileSync(emailPath, 'utf8');
};
const removeQuotedHTML = function(fname, opts) {
if (opts == null) {
opts = {};
}
const removeQuotedHTML = function(fname, opts = {}) {
return QuotedHTMLTransformer.removeQuotedHTML(readFile(fname), opts);
};

View file

@ -15,10 +15,7 @@ const _ = require('underscore');
// forward.
class TimeOverride {
static initClass() {
this.advanceClock = delta => {
if (delta == null) {
delta = 1;
}
this.advanceClock = (delta = 1) => {
this.now += delta;
const callbacks = [];

View file

@ -64,9 +64,9 @@ module.exports = class ApplicationMenu {
}
const focusHandler = () => {
let template;
this.lastFocusedWindow = window;
if ((template = this.windowTemplates.get(window))) {
const template = this.windowTemplates.get(window);
if (template) {
this.setActiveTemplate(template);
}
};
@ -135,8 +135,8 @@ module.exports = class ApplicationMenu {
// Replaces VERSION with the current version.
extendTemplateWithVersion(template) {
let item;
if ((item = this.flattenMenuTemplate(template).find(({ label }) => label === 'VERSION'))) {
const item = this.flattenMenuTemplate(template).find(({ label }) => label === 'VERSION');
if (item) {
item.label = `Version ${this.version}`;
}
}

View file

@ -45,7 +45,9 @@ export default class AutoUpdateManager extends EventEmitter {
host = `updates-staging.getmailspring.com`;
}
this.feedURL = `https://${host}/check/${params.platform}/${params.arch}/${params.version}/${params.id}/${params.channel}`;
this.feedURL = `https://${host}/check/${params.platform}/${params.arch}/${params.version}/${
params.id
}/${params.channel}`;
if (autoUpdater) {
autoUpdater.setFeedURL(this.feedURL);
}

View file

@ -55,11 +55,13 @@ export default class ConfigPersistenceManager {
let detail = error.message;
if (error instanceof SyntaxError) {
detail += `\n\nThe file ${this
.configFilePath} has incorrect JSON formatting or is empty. Fix the formatting to resolve this error, or reset your settings to continue using N1.`;
detail += `\n\nThe file ${
this.configFilePath
} has incorrect JSON formatting or is empty. Fix the formatting to resolve this error, or reset your settings to continue using N1.`;
} else {
detail += `\n\nWe were unable to read the file ${this
.configFilePath}. Make sure you have permissions to access this file, and check that the file is not open or being edited and try again.`;
detail += `\n\nWe were unable to read the file ${
this.configFilePath
}. Make sure you have permissions to access this file, and check that the file is not open or being edited and try again.`;
}
const clickedIndex = dialog.showMessageBox({
@ -123,8 +125,9 @@ export default class ConfigPersistenceManager {
const clickedIndex = dialog.showMessageBox({
type: 'error',
message: `Failed to save "${path.basename(this.configFilePath)}"`,
detail: `\n\nWe were unable to save the file ${this
.configFilePath}. Make sure you have permissions to access this file, and check that the file is not open or being edited and try again.`,
detail: `\n\nWe were unable to save the file ${
this.configFilePath
}. Make sure you have permissions to access this file, and check that the file is not open or being edited and try again.`,
buttons: ['Okay', 'Try again'],
});
return ['ignore', 'retry'][clickedIndex];

View file

@ -10,23 +10,20 @@ let idNum = 0;
module.exports = class MailspringWindow extends EventEmitter {
static includeShellLoadTime = true;
constructor(settings) {
constructor(settings = {}) {
super();
let frame, height, pathToOpen, resizable, title, toolbar, width;
let frame, height, pathToOpen, resizable, title, width;
this.browserWindow = null;
this.loaded = null;
this.isSpec = null;
if (settings == null) {
settings = {};
}
({
frame,
title,
width,
height,
toolbar,
// toolbar, present but passed through to client-side
resizable,
pathToOpen,
isSpec: this.isSpec,

View file

@ -93,7 +93,9 @@ export default class WindowManager {
if (this._windows[win.windowKey]) {
throw new Error(
`WindowManager: Attempting to register a new window for an existing windowKey (${win.windowKey}). Use 'get()' to retrieve the existing window instead.`
`WindowManager: Attempting to register a new window for an existing windowKey (${
win.windowKey
}). Use 'get()' to retrieve the existing window instead.`
);
}

View file

@ -28,7 +28,8 @@ function ImageNode(props) {
onRemoveAttachment={() =>
editor.change(change => {
change.removeNodeByKey(node.key);
})}
})
}
/>
);
}

View file

@ -9,10 +9,8 @@ const {
ReactDOM,
PropTypes,
Utils,
RegExpUtils,
IdentityStore,
MailspringAPIRequest,
SearchableComponentMaker,
SearchableComponentStore,
} = require('mailspring-exports');
const IFrameSearcher = require('../searchable-components/iframe-searcher').default;

View file

@ -1,4 +1,3 @@
const _ = require('underscore');
const SwipeContainer = require('./swipe-container').default;
const { React, PropTypes, Utils } = require('mailspring-exports');

View file

@ -24,10 +24,7 @@ class MailImportantIcon extends React.Component {
this.state = this.getState();
}
getState = props => {
if (props == null) {
({ props } = this);
}
getState = (props = this.props) => {
let category = null;
let visible = false;

View file

@ -145,12 +145,8 @@ class MultiselectActionBar extends React.Component {
}
}
_getStateFromStores(props) {
let left;
if (props == null) {
({ props } = this);
}
return { items: (left = props.dataSource.selection.items()) != null ? left : [] };
_getStateFromStores(props = this.props) {
return { items: props.dataSource.selection.items() || [] };
}
_onChange = () => {

View file

@ -67,10 +67,7 @@ module.exports = class MultiselectListInteractionHandler {
this.props.dataSource.selection.toggle(this.props.dataSource.getById(id));
};
onShift = (delta, options) => {
if (options == null) {
options = {};
}
onShift = (delta, options = {}) => {
const { id, action } = this._keyboardContext();
const current = this.props.dataSource.getById(id);

View file

@ -57,10 +57,9 @@ class MultiselectList extends React.Component {
prevProps.focusedId !== this.props.focusedId ||
prevProps.keyboardCursorId !== this.props.keyboardCursorId
) {
let item = ReactDOM.findDOMNode(this).querySelector('.focused');
if (item == null) {
item = ReactDOM.findDOMNode(this).querySelector('.keyboard-cursor');
}
const item =
ReactDOM.findDOMNode(this).querySelector('.focused') ||
ReactDOM.findDOMNode(this).querySelector('.keyboard-cursor');
if (!(item instanceof Node)) {
return;
}

View file

@ -64,13 +64,12 @@ module.exports = class MultiselectSplitInteractionHandler {
};
onShift = (delta, options) => {
let action, id, selection;
if (options.select) {
this._turnFocusIntoSelection();
}
let action, id;
if (this.props.dataSource.selection.count() > 0) {
({ selection } = this.props.dataSource);
const keyboardId = this.props.keyboardCursorId;
id = keyboardId != null ? keyboardId : this.props.dataSource.selection.top().id;
action = this.onSetCursorPosition;

View file

@ -93,10 +93,7 @@ class Scrollbar extends React.Component {
);
}
recomputeDimensions = options => {
if (options == null) {
options = {};
}
recomputeDimensions = (options = {}) => {
if (this.props.getScrollRegion != null) {
this.props.getScrollRegion()._recomputeDimensions(options);
}
@ -356,10 +353,7 @@ class ScrollRegion extends React.Component {
// Public: Scroll to the DOM Node provided.
//
scrollTo = (node, param) => {
if (param == null) {
param = {};
}
scrollTo = (node, param = {}) => {
const { position, settle, done } = param;
if (node instanceof React.Component) {
node = ReactDOM.findDOMNode(node);
@ -376,10 +370,7 @@ class ScrollRegion extends React.Component {
// a ClientRect or similar object with top, left, width, height relative to the
// window, not the scroll region. This is designed to make it easy to use with
// node.getBoundingClientRect()
scrollToRect(rect, param) {
if (param == null) {
param = {};
}
scrollToRect(rect, param = {}) {
const { position, settle, done } = param;
if (rect instanceof Node) {
throw new Error('ScrollRegion.scrollToRect: requires a rect. Maybe you meant scrollTo?');
@ -473,17 +464,8 @@ class ScrollRegion extends React.Component {
scrollIfSettled();
};
recomputeDimensions(options) {
let left;
if (options == null) {
options = {};
}
const scrollbar =
(left =
typeof this.props.getScrollbar === 'function' ? this.props.getScrollbar() : undefined) !=
null
? left
: this.refs.scrollbar;
recomputeDimensions(options = {}) {
const scrollbar = this.props.getScrollbar ? this.props.getScrollbar() : this.refs.scrollbar;
if (scrollbar) {
scrollbar._recomputeDimensions(options);
}
@ -509,8 +491,6 @@ class ScrollRegion extends React.Component {
if (useCachedValues) {
totalHeight =
this.state.totalHeight != null ? this.state.totalHeight : contentNode.scrollHeight;
const trackHeight =
this.state.trackHeight != null ? this.state.trackHeight : contentNode.scrollHeight;
viewportHeight =
this.state.viewportHeight != null ? this.state.viewportHeight : contentNode.clientHeight;
} else {
@ -528,13 +508,7 @@ class ScrollRegion extends React.Component {
};
_setSharedState(state) {
let left;
const scrollbar =
(left =
typeof this.props.getScrollbar === 'function' ? this.props.getScrollbar() : undefined) !=
null
? left
: this.refs.scrollbar;
const scrollbar = this.props.getScrollbar ? this.props.getScrollbar() : this.refs.scrollbar;
if (scrollbar) {
scrollbar.setStateFromScrollRegion(state);
}

View file

@ -522,8 +522,7 @@ class Config {
*/
pushAtKeyPath(keyPath, value) {
let left;
const arrayValue = (left = this.get(keyPath)) != null ? left : [];
const arrayValue = this.get(keyPath) || [];
if (!(arrayValue instanceof Array)) {
throw new Error(
`Config.pushAtKeyPath is intended for array values. Value ${JSON.stringify(
@ -537,8 +536,7 @@ class Config {
}
unshiftAtKeyPath(keyPath, value) {
let left;
const arrayValue = (left = this.get(keyPath)) != null ? left : [];
const arrayValue = this.get(keyPath) || [];
if (!(arrayValue instanceof Array)) {
throw new Error(
`Config.unshiftAtKeyPath is intended for array values. Value ${JSON.stringify(
@ -552,8 +550,7 @@ class Config {
}
removeAtKeyPath(keyPath, value) {
let left;
const arrayValue = (left = this.get(keyPath)) != null ? left : [];
const arrayValue = this.get(keyPath) || [];
if (!(arrayValue instanceof Array)) {
throw new Error(
`Config.removeAtKeyPath is intended for array values. Value ${JSON.stringify(
@ -703,8 +700,8 @@ class Config {
}
makeValueConformToSchema(keyPath, value) {
let schema;
if ((schema = this.getSchema(keyPath))) {
let schema = this.getSchema(keyPath);
if (schema) {
value = this.constructor.executeSchemaEnforcers(keyPath, value, schema);
}
return value;
@ -759,7 +756,7 @@ class Config {
Config.addSchemaEnforcers({
integer: {
coerce(keyPath, value, schema) {
value = parseInt(value);
value = parseInt(value, 10);
if (isNaN(value) || !isFinite(value)) {
throw new Error(
`Validation failed at ${keyPath}, ${JSON.stringify(value)} cannot be coerced into an int`

View file

@ -129,8 +129,9 @@ class Mac {
}
getLaunchServicesPlistPath(callback) {
const secure = `${process.env
.HOME}/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist`;
const secure = `${
process.env.HOME
}/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist`;
const insecure = `${process.env.HOME}/Library/Preferences/com.apple.LaunchServices.plist`;
fs.exists(secure, exists => (exists ? callback(secure) : callback(insecure)));

View file

@ -88,7 +88,7 @@ var DOMUtils = {
commonAncestor(nodes, parentFilter) {
if (nodes == null) {
nodes = [];
return null;
}
if (nodes.length === 0) {
return null;
@ -104,6 +104,7 @@ var DOMUtils = {
const getParents = function(node) {
const parentNodes = [node];
let depth = 0;
// eslint-disable-next-line
while ((node = node.parentNode)) {
if (parentFilter) {
if (parentFilter(node)) {
@ -185,6 +186,7 @@ var DOMUtils = {
replacedNodes.unshift(lastChild);
parent.replaceChild(lastChild, node);
// eslint-disable-next-line
while ((child = _.last(node.childNodes))) {
replacedNodes.unshift(child);
parent.insertBefore(child, lastChild);

View file

@ -47,8 +47,9 @@ export default class Attribute {
}
if (val.length === 0) {
console.warn(
`Attribute::in (${this
.modelKey}) called with an empty set. You should avoid this useless query!`
`Attribute::in (${
this.modelKey
}) called with an empty set. You should avoid this useless query!`
);
}
if (val.length === 1) {

View file

@ -84,8 +84,9 @@ export async function makeRequest(options) {
}
if (!resp.ok) {
error.statusCode = resp.status;
error.message = `${options.method ||
'GET'} ${options.url} returned ${resp.status} ${resp.statusText}`;
error.message = `${options.method || 'GET'} ${options.url} returned ${resp.status} ${
resp.statusText
}`;
throw error;
}
return resp.json();

View file

@ -217,7 +217,9 @@ export default class MailsyncBridge {
AppEnv.showErrorDialog({
title: `Cleanup Started`,
message: `Mailspring is clearing it's cache for ${account.emailAddress}. Depending on the size of the mailbox, this may take a few seconds or a few minutes. An alert will appear when cleanup is complete.`,
message: `Mailspring is clearing it's cache for ${
account.emailAddress
}. Depending on the size of the mailbox, this may take a few seconds or a few minutes. An alert will appear when cleanup is complete.`,
});
try {

View file

@ -14,10 +14,7 @@ const DatabaseObjectRegistry = require('../../registries/database-object-registr
let imageData = null;
module.exports = Utils = {
waitFor(latch, options) {
if (options == null) {
options = {};
}
waitFor(latch, options = {}) {
const timeout = options.timeout || 400;
const expire = Date.now() + timeout;
return new Promise(function(resolve, reject) {
@ -41,10 +38,7 @@ module.exports = Utils = {
return files.find(f => !f.contentId || f.size > 12 * 1024);
},
extractTextFromHtml(html, param) {
if (param == null) {
param = {};
}
extractTextFromHtml(html, param = {}) {
const { maxLength } = param;
if ((html != null ? html : '').trim().length === 0) {
return '';
@ -97,10 +91,7 @@ module.exports = Utils = {
return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&');
},
range(left, right, inclusive) {
if (inclusive == null) {
inclusive = true;
}
range(left, right, inclusive = true) {
let range = [];
let ascending = left < right;
let end = !inclusive ? right : ascending ? right + 1 : right - 1;
@ -115,24 +106,15 @@ module.exports = Utils = {
//
// See regex explanation and test here:
// https://regex101.com/r/zG7aW4/2
wordSearchRegExp(str) {
if (str == null) {
str = '';
}
wordSearchRegExp(str = '') {
return new RegExp(`((?:^|\\W|$)${Utils.escapeRegExp(str.trim())})`, 'ig');
},
// Takes an optional customizer. The customizer is passed the key and the
// new cloned value for that key. The customizer is expected to either
// modify the value and return it or simply be the identity function.
deepClone(object, customizer, stackSeen, stackRefs) {
deepClone(object, customizer, stackSeen = [], stackRefs = []) {
let newObject;
if (stackSeen == null) {
stackSeen = [];
}
if (stackRefs == null) {
stackRefs = [];
}
if (!_.isObject(object)) {
return object;
}
@ -172,10 +154,7 @@ module.exports = Utils = {
return newObject;
},
toSet(arr) {
if (arr == null) {
arr = [];
}
toSet(arr = []) {
const set = {};
for (let item of arr) {
set[item] = true;
@ -185,19 +164,9 @@ module.exports = Utils = {
// Given a File object or uploadData of an uploading file object,
// determine if it looks like an image and is in the size range for previews
shouldDisplayAsImage(file) {
let left, left1, left2;
if (file == null) {
file = {};
}
const name =
(left =
(left1 = file.filename != null ? file.filename : file.fileName) != null
? left1
: file.name) != null
? left
: '';
const size = (left2 = file.size != null ? file.size : file.fileSize) != null ? left2 : 0;
shouldDisplayAsImage(file = {}) {
const name = file.filename || file.fileName || file.name;
const size = file.size || file.fileSize || 0;
const ext = path.extname(name).toLowerCase();
const extensions = ['.jpg', '.bmp', '.gif', '.png', '.jpeg'];
@ -263,9 +232,8 @@ module.exports = Utils = {
}
if (!imageData) {
let left, left1;
imageData = (left = AppEnv.fileListCache().imageData) != null ? left : '{}';
Utils.images = (left1 = JSON.parse(imageData)) != null ? left1 : {};
imageData = AppEnv.fileListCache().imageData || '{}';
Utils.images = JSON.parse(imageData) || {};
}
if (!Utils.images || !Utils.images[resourcePath]) {
@ -341,10 +309,7 @@ module.exports = Utils = {
if (args.length < 2) {
return false;
}
const domains = args.map(function(email) {
if (email == null) {
email = '';
}
const domains = args.map((email = '') => {
return _.last(
email
.toLowerCase()
@ -356,10 +321,7 @@ module.exports = Utils = {
return _.every(domains, domain => domain.length > 0 && toMatch === domain);
},
emailHasCommonDomain(email) {
if (email == null) {
email = '';
}
emailHasCommonDomain(email = '') {
const domain = _.last(
email
.toLowerCase()
@ -399,10 +361,7 @@ module.exports = Utils = {
return !(r2.left > r1.right || r2.right < r1.left || r2.top > r1.bottom || r2.bottom < r1.top);
},
isEqualReact(a, b, options) {
if (options == null) {
options = {};
}
isEqualReact(a, b, options = {}) {
options.functionsAreEqual = true;
options.ignoreKeys = (options.ignoreKeys != null ? options.ignoreKeys : []).push('id');
return Utils.isEqual(a, b, options);
@ -413,10 +372,7 @@ module.exports = Utils = {
// - functionsAreEqual: if true then all functions are equal
// - keysToIgnore: an array of object keys to ignore checks on
// - logWhenFalse: logs when isEqual returns false
isEqual(a, b, options) {
if (options == null) {
options = {};
}
isEqual(a, b, options = {}) {
const value = Utils._isEqual(a, b, [], [], options);
if (options.logWhenFalse) {
if (value === false) {
@ -428,13 +384,10 @@ module.exports = Utils = {
return value;
},
_isEqual(a, b, aStack, bStack, options) {
_isEqual(a, b, aStack, bStack, options = {}) {
// Identical objects are equal. `0 is -0`, but they aren't identical.
// See the [Harmony `egal`
// proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
if (options == null) {
options = {};
}
if (a === b) {
return a !== 0 || 1 / a === 1 / b;
}

View file

@ -150,7 +150,9 @@ class FeatureUsageStore extends MailspringStore {
} else if (featureData.period === 'yearly') {
time = 'a year';
}
rechargeText = `You can ${lexicon.usagePhrase} ${featureData.quota} emails ${time} with Mailspring Basic. Upgrade to Pro today!`;
rechargeText = `You can ${lexicon.usagePhrase} ${
featureData.quota
} emails ${time} with Mailspring Basic. Upgrade to Pro today!`;
}
return { headerText, rechargeText };
}

View file

@ -141,31 +141,30 @@ class MessageBodyProcessor {
// Sanitizing <script> tags, etc. isn't necessary because we use CORS rules
// to prevent their execution and sandbox content in the iFrame, but we still
// want to remove contenteditable attributes and other strange things.
return SanitizeTransformer.run(
message.body,
SanitizeTransformer.Preset.UnsafeOnly
).then(sanitized => {
let body = sanitized;
for (const extension of MessageStore.extensions()) {
if (!extension.formatMessageBody) {
continue;
}
return SanitizeTransformer.run(message.body, SanitizeTransformer.Preset.UnsafeOnly).then(
sanitized => {
let body = sanitized;
for (const extension of MessageStore.extensions()) {
if (!extension.formatMessageBody) {
continue;
}
// Give each extension the message object to process the body, but don't
// allow them to modify anything but the body for the time being.
const previousBody = body;
try {
const virtual = message.clone();
virtual.body = body;
extension.formatMessageBody({ message: virtual });
body = virtual.body;
} catch (err) {
AppEnv.reportError(err);
body = previousBody;
// Give each extension the message object to process the body, but don't
// allow them to modify anything but the body for the time being.
const previousBody = body;
try {
const virtual = message.clone();
virtual.body = body;
extension.formatMessageBody({ message: virtual });
body = virtual.body;
} catch (err) {
AppEnv.reportError(err);
body = previousBody;
}
}
return body;
}
return body;
});
);
}
_addToCache(key, body) {

View file

@ -237,15 +237,9 @@ class WorkspaceStore extends MailspringStore {
// *`columns` An {Object} with keys for each layout mode the Sheet
// supports. For each key, provide an array of column names.
//
defineSheet(id, options, columns) {
defineSheet(id, options = {}, columns = {}) {
// Make sure all the locations have definitions so that packages
// can register things into these locations and their toolbars.
if (options == null) {
options = {};
}
if (columns == null) {
columns = {};
}
for (let layout in columns) {
const cols = columns[layout];
for (let idx = 0; idx < cols.length; idx++) {

View file

@ -140,14 +140,14 @@ export default class SendDraftTask extends Task {
const [smtpError, emails] = debuginfo.split(':::');
errorMessage =
"We were unable to deliver this message to some recipients. Click 'See Details' for more information.";
errorDetail = `We encountered an SMTP Gateway error that prevented this message from being delivered to all recipients. The message was only sent successfully to these recipients:\n${emails}\n\nError: ${LocalizedErrorStrings[
smtpError
]}`;
errorDetail = `We encountered an SMTP Gateway error that prevented this message from being delivered to all recipients. The message was only sent successfully to these recipients:\n${emails}\n\nError: ${
LocalizedErrorStrings[smtpError]
}`;
} else if (key === 'send-failed') {
errorMessage = `We were unable to deliver this message. ${LocalizedErrorStrings[debuginfo]}`;
errorDetail = `We encountered an SMTP error that prevented this message from being delivered:\n\n${LocalizedErrorStrings[
debuginfo
]}`;
errorDetail = `We encountered an SMTP error that prevented this message from being delivered:\n\n${
LocalizedErrorStrings[debuginfo]
}`;
} else {
errorMessage = 'We were unable to deliver this message.';
errorDetail = `An unknown error occurred: ${JSON.stringify({ key, debuginfo })}`;

View file

@ -51,13 +51,13 @@ const CategoryObservables = {
},
standard(account) {
const observable = Rx.Observable
.fromConfig('core.workspace.showImportant')
.flatMapLatest(showImportant => {
const observable = Rx.Observable.fromConfig('core.workspace.showImportant').flatMapLatest(
showImportant => {
return CategoryObservables.forAccount(account)
.sort()
.categoryFilter(cat => cat.isStandardCategory(showImportant));
});
}
);
Object.assign(observable, CategoryOperators);
return observable;
},

View file

@ -78,6 +78,7 @@ export default class MailspringStore {
stopListeningToAll() {
let remaining = undefined;
const subs = this.subscriptions || [];
// eslint-disable-next-line
while ((remaining = subs.length)) {
subs[0].stop();
if (subs.length !== remaining - 1) {

View file

@ -85,8 +85,7 @@ export function ActionTemplatesForAccount(account) {
const templates = [].concat(ActionTemplates);
const CategoryNamesObservable = MailspringObservables.Categories
.forAccount(account)
const CategoryNamesObservable = MailspringObservables.Categories.forAccount(account)
.sort()
.map(cats => cats.filter(cat => !cat.isLockedCategory()))
.map(cats =>

View file

@ -94,7 +94,9 @@ export default class PackageManager {
if (!pkg.json.engines.mailspring) {
// don't use AppEnv.reportError, I don't want to know about these.
console.error(
`This plugin or theme ${pkg.name} does not list "mailspring" in it's package.json's "engines" field. Ask the developer to test the plugin with Mailspring and add it, or follow the instructions here: http://support.getmailspring.com/hc/en-us/articles/115001918391`
`This plugin or theme ${
pkg.name
} does not list "mailspring" in it's package.json's "engines" field. Ask the developer to test the plugin with Mailspring and add it, or follow the instructions here: http://support.getmailspring.com/hc/en-us/articles/115001918391`
);
return;
}

View file

@ -59,11 +59,7 @@ const RegExpUtils = {
},
// Test cases: https://regex101.com/r/pD7iS5/4
urlRegex(param) {
if (param == null) {
param = {};
}
const { matchStartOfString, matchTailOfString } = param;
urlRegex({ matchStartOfString, matchTailOfString } = {}) {
const commonTlds = [
'com',
'org',
@ -207,11 +203,7 @@ const RegExpUtils = {
return /["|']https:\/\/link\.getmailspring\.com\/link\/.*?\?.*?redirect=([^&"']*).*?["|']/g;
},
punctuation(param) {
if (param == null) {
param = {};
}
let { exclude } = param;
punctuation({ exclude } = {}) {
if (exclude == null) {
exclude = [];
}

View file

@ -224,8 +224,9 @@ class StructuredSearchQueryVisitor extends SearchQueryExpressionVisitor {
// in sqlite3, you use '' to escape a '. Weird right?
const escaped = node.rawQuery.replace(/'/g, "''");
this._result = `(\`${this
._className}\`.\`id\` IN (SELECT \`content_id\` FROM \`${searchTable}\` WHERE \`${searchTable}\` MATCH '${escaped}' LIMIT 1000))`;
this._result = `(\`${
this._className
}\`.\`id\` IN (SELECT \`content_id\` FROM \`${searchTable}\` WHERE \`${searchTable}\` MATCH '${escaped}' LIMIT 1000))`;
}
}

View file

@ -27,12 +27,12 @@
"electron-packager": "8.7.x",
"electron-winstaller": "2.x.x",
"eslint": "^4.7.2",
"eslint-config-prettier": "^2.6.0",
"eslint-config-prettier": "^2.9.0",
"eslint-config-react-app": "^2.0.0",
"eslint-plugin-flowtype": "^2.36.0",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-prettier": "^2.3.1",
"eslint-plugin-prettier": "^2.5.0",
"eslint-plugin-react": "^7.4.0",
"eslint_d": "4.2.0",
"fs-extra": "2.x.x",
@ -55,8 +55,7 @@
"load-grunt-parent-tasks": "0.1.1",
"meta-marked": "^0.4.2",
"mkdirp": "^0.5.1",
"pm2": "2.4.0",
"prettier": "^1.7.0",
"prettier": "^1.10.0",
"request": "2.x.x",
"rimraf": "^2.6.1",
"targz": "^1.0.1",