diff --git a/app/__jest__/setup.js b/app/__jest__/setup.js index 159a704a9..6c3cd0a51 100644 --- a/app/__jest__/setup.js +++ b/app/__jest__/setup.js @@ -16,6 +16,8 @@ const localStorageMock = (function () { }; })(); +// Don't console log during testing. It's annoying +global.console.log = () => null; global.localStorage = localStorageMock; global.requestAnimationFrame = cb => process.nextTick(cb); global.require = require; diff --git a/app/common/__tests__/database.test.js b/app/common/__tests__/database.test.js index d40693a0c..bf1ebc241 100644 --- a/app/common/__tests__/database.test.js +++ b/app/common/__tests__/database.test.js @@ -68,7 +68,7 @@ describe('bufferChanges()', () => { }; db.onChange(callback); - db.bufferChanges(); + await db.bufferChanges(); const newDoc = await models.request.create(doc); const updatedDoc = await models.request.update(newDoc, true); @@ -76,14 +76,14 @@ describe('bufferChanges()', () => { expect(changesSeen.length).toBe(0); // Assert changes seen after flush - db.flushChanges(); + await db.flushChanges(); expect(changesSeen).toEqual([[ [db.CHANGE_INSERT, newDoc, false], [db.CHANGE_UPDATE, updatedDoc, false] ]]); // Assert no more changes seen after flush again - db.flushChanges(); + await db.flushChanges(); expect(changesSeen).toEqual([[ [db.CHANGE_INSERT, newDoc, false], [db.CHANGE_UPDATE, updatedDoc, false] @@ -157,3 +157,130 @@ describe('requestGroupDuplicate()', () => { expect(newChildRequestGroups.length).toBe(1); }); }); + +describe('_fixThings()', () => { + beforeEach(globalBeforeEach); + it('fixes duplicate environments', async () => { + // Create Workspace with no children + const workspace = await models.workspace.create({_id: 'w1'}); + expect((await db.withDescendants(workspace)).length).toBe(1); + + // Create one set of sub environments + await models.environment.create({_id: 'b1', parentId: 'w1', data: {foo: 'b1', b1: true}}); + await models.environment.create({_id: 'b1_sub1', parentId: 'b1', data: {foo: '1'}}); + await models.environment.create({_id: 'b1_sub2', parentId: 'b1', data: {foo: '2'}}); + + // Create second set of sub environments + await models.environment.create({_id: 'b2', parentId: 'w1', data: {foo: 'b2', b2: true}}); + await models.environment.create({_id: 'b2_sub1', parentId: 'b2', data: {foo: '3'}}); + await models.environment.create({_id: 'b2_sub2', parentId: 'b2', data: {foo: '4'}}); + + // Make sure we have everything + expect((await db.withDescendants(workspace)).length).toBe(7); + const descendants = (await db.withDescendants(workspace)).map(d => ({ + _id: d._id, + parentId: d.parentId, + data: d.data || null + })); + expect(descendants).toEqual([ + {_id: 'w1', data: null, parentId: null}, + {_id: 'b1', data: {foo: 'b1', b1: true}, parentId: 'w1'}, + {_id: 'b2', data: {foo: 'b2', b2: true}, parentId: 'w1'}, + {_id: 'b1_sub1', data: {foo: '1'}, parentId: 'b1'}, + {_id: 'b1_sub2', data: {foo: '2'}, parentId: 'b1'}, + {_id: 'b2_sub1', data: {foo: '3'}, parentId: 'b2'}, + {_id: 'b2_sub2', data: {foo: '4'}, parentId: 'b2'} + ]); + + // Run the fix algorithm + await db._repairDatabase(); + + // Make sure things get adjusted + const descendants2 = (await db.withDescendants(workspace)).map( + d => ({_id: d._id, parentId: d.parentId, data: d.data || null}) + ); + expect(descendants2).toEqual([ + {_id: 'w1', data: null, parentId: null}, + {_id: 'b1', data: {foo: 'b1', b1: true, b2: true}, parentId: 'w1'}, + + // Extra base environments should have been deleted + // {_id: 'b2', data: {foo: 'bar'}, parentId: 'w1'}, + + // Sub environments should have been moved to new "master" base environment + {_id: 'b1_sub1', data: {foo: '1'}, parentId: 'b1'}, + {_id: 'b1_sub2', data: {foo: '2'}, parentId: 'b1'}, + {_id: 'b2_sub1', data: {foo: '3'}, parentId: 'b1'}, + {_id: 'b2_sub2', data: {foo: '4'}, parentId: 'b1'} + ]); + }); + + it('fixes duplicate cookie jars', async () => { + // Create Workspace with no children + const workspace = await models.workspace.create({_id: 'w1'}); + expect((await db.withDescendants(workspace)).length).toBe(1); + + // Create one set of sub environments + await models.cookieJar.create({ + _id: 'j1', + parentId: 'w1', + cookies: [ + {id: '1', key: 'foo', value: '1'}, + {id: 'j1_1', key: 'j1', value: '1'} + ] + }); + + await models.cookieJar.create({ + _id: 'j2', + parentId: 'w1', + cookies: [ + {id: '1', key: 'foo', value: '2'}, + {id: 'j2_1', key: 'j2', value: '2'} + ] + }); + + // Make sure we have everything + expect((await db.withDescendants(workspace)).length).toBe(3); + const descendants = (await db.withDescendants(workspace)).map( + d => ({_id: d._id, cookies: d.cookies || null, parentId: d.parentId}) + ); + expect(descendants).toEqual([ + {_id: 'w1', cookies: null, parentId: null}, + { + _id: 'j1', + parentId: 'w1', + cookies: [ + {id: '1', key: 'foo', value: '1'}, + {id: 'j1_1', key: 'j1', value: '1'} + ] + }, + { + _id: 'j2', + parentId: 'w1', + cookies: [ + {id: '1', key: 'foo', value: '2'}, + {id: 'j2_1', key: 'j2', value: '2'} + ] + } + ]); + + // Run the fix algorithm + await db._repairDatabase(); + + // Make sure things get adjusted + const descendants2 = (await db.withDescendants(workspace)).map( + d => ({_id: d._id, cookies: d.cookies || null, parentId: d.parentId}) + ); + expect(descendants2).toEqual([ + {_id: 'w1', cookies: null, parentId: null}, + { + _id: 'j1', + parentId: 'w1', + cookies: [ + {id: '1', key: 'foo', value: '1'}, + {id: 'j1_1', key: 'j1', value: '1'}, + {id: 'j2_1', key: 'j2', value: '2'} + ] + } + ]); + }); +}); diff --git a/app/common/__tests__/import.test.js b/app/common/__tests__/import.test.js index d17d39d32..1b4d4be78 100644 --- a/app/common/__tests__/import.test.js +++ b/app/common/__tests__/import.test.js @@ -1,5 +1,5 @@ import * as models from '../../models'; -import * as importUtil from '../../ui/import'; +import * as importUtil from '../import'; import {getAppVersion} from '../constants'; import {globalBeforeEach} from '../../__jest__/before-each'; diff --git a/app/common/__tests__/misc.test.js b/app/common/__tests__/misc.test.js index 8eb84ac7d..638216a80 100644 --- a/app/common/__tests__/misc.test.js +++ b/app/common/__tests__/misc.test.js @@ -179,13 +179,8 @@ describe('keyedDebounce()', () => { beforeEach(async () => { await globalBeforeEach(); jest.useFakeTimers(); - - // There has to be a better way to reset this... - setTimeout.mock.calls = []; }); - afterEach(() => jest.clearAllTimers()); - it('debounces correctly', () => { const resultsList = []; const fn = misc.keyedDebounce(results => { @@ -215,13 +210,8 @@ describe('debounce()', () => { beforeEach(async () => { await globalBeforeEach(); jest.useFakeTimers(); - - // There has to be a better way to reset this... - setTimeout.mock.calls = []; }); - afterEach(() => jest.clearAllTimers()); - it('debounces correctly', () => { const resultList = []; const fn = misc.debounce((...args) => { diff --git a/app/common/database.js b/app/common/database.js index 11efc10cf..3a37a6683 100644 --- a/app/common/database.js +++ b/app/common/database.js @@ -59,7 +59,7 @@ export async function init ( // Fill in the defaults for (const modelType of types) { if (db[modelType]) { - console.warn(`[db] Already initialized DB.${modelType}`); + console.log(`[db] Already initialized DB.${modelType}`); continue; } @@ -81,7 +81,16 @@ export async function init ( e.sender.send(replyChannel, result); }); - console.log(`[db] Initialized DB at ${getDBFilePath('$TYPE')}`); + // NOTE: Only repair the DB if we're not running in memory. Repairing here causes tests to + // hang indefinitely for some reason. + // TODO: Figure out why this makes tests hang + if (!config.inMemoryOnly) { + await _repairDatabase(); + } + + if (!config.inMemoryOnly) { + console.log(`[db] Initialized DB at ${getDBFilePath('$TYPE')}`); + } } // ~~~~~~~~~~~~~~~~ // @@ -100,16 +109,19 @@ export function offChange (callback: Function): void { changeListeners = changeListeners.filter(l => l !== callback); } -export const bufferChanges = database.bufferChanges = function (millis: number = 1000): void { - if (db._empty) { - _send('bufferChanges', ...arguments); - return; - } +export const bufferChanges = database.bufferChanges = async function (millis: number = 1000): Promise { + if (db._empty) return _send('bufferChanges', ...arguments); bufferingChanges = true; setTimeout(database.flushChanges, millis); }; +export const flushChangesAsync = database.flushChangesAsync = async function (): Promise { + process.nextTick(async () => { + await flushChanges(); + }); +}; + export const flushChanges = database.flushChanges = async function (): Promise { if (db._empty) return _send('flushChanges', ...arguments); @@ -314,7 +326,7 @@ export const remove = database.remove = async function ( ): Promise { if (db._empty) return _send('remove', ...arguments); - database.bufferChanges(); + await database.bufferChanges(); const docs = await database.withDescendants(doc); const docIds = docs.map(d => d._id); @@ -325,7 +337,7 @@ export const remove = database.remove = async function ( docs.map(d => notifyOfChange(CHANGE_REMOVE, d, fromSync)); - database.flushChanges(); + await database.flushChanges(); }; export const removeWhere = database.removeWhere = async function ( @@ -334,7 +346,7 @@ export const removeWhere = database.removeWhere = async function ( ): Promise { if (db._empty) return _send('removeWhere', ...arguments); - database.bufferChanges(); + await database.bufferChanges(); for (const doc of await database.find(type, query)) { const docs = await database.withDescendants(doc); @@ -347,7 +359,7 @@ export const removeWhere = database.removeWhere = async function ( docs.map(d => notifyOfChange(CHANGE_REMOVE, d, false)); } - database.flushChanges(); + await database.flushChanges(); }; // ~~~~~~~~~~~~~~~~~~~ // @@ -481,7 +493,7 @@ export const duplicate = database.duplicate = async function ( ): Promise { if (db._empty) return _send('duplicate', ...arguments); - database.bufferChanges(); + await database.bufferChanges(); async function next (docToCopy: T, patch: Object): Promise { // 1. Copy the doc @@ -511,7 +523,7 @@ export const duplicate = database.duplicate = async function ( const createdDoc = await next(originalDoc, patch); - database.flushChanges(); + await database.flushChanges(); return createdDoc; }; @@ -529,3 +541,87 @@ async function _send (fnName: string, ...args: Array): Promise { }); }); } + +/** + * Run various database repair scripts + */ +export async function _repairDatabase () { + console.log(`[fix] Running database repairs`); + for (const workspace of await find(models.workspace.type)) { + await _repairBaseEnvironments(workspace); + await _fixMultipleCookieJars(workspace); + } +} + +/** + * This function repairs workspaces that have multiple base environments. Since a workspace + * can only have one, this function walks over all base environments, merges the data, and + * moves all children as well. + */ +async function _repairBaseEnvironments (workspace) { + const baseEnvironments = await find(models.environment.type, {parentId: workspace._id}); + + // Nothing to do here + if (baseEnvironments.length <= 1) { + return; + } + + const chosenBase = baseEnvironments[0]; + for (const baseEnvironment of baseEnvironments) { + if (baseEnvironment._id === chosenBase._id) { + continue; + } + + chosenBase.data = Object.assign(baseEnvironment.data, chosenBase.data); + const subEnvironments = await find(models.environment.type, {parentId: baseEnvironment._id}); + + for (const subEnvironment of subEnvironments) { + await docUpdate(subEnvironment, {parentId: chosenBase._id}); + } + + // Remove unnecessary base env + await remove(baseEnvironment); + } + + // Update remaining base env + await update(chosenBase); + + console.log(`[fix] Merged ${baseEnvironments.length} base environments under ${workspace.name}`); +} + +/** + * This function repairs workspaces that have multiple cookie jars. Since a workspace + * can only have one, this function walks over all jars and merges them and their cookies + * together. + */ +async function _fixMultipleCookieJars (workspace) { + const cookieJars = await find(models.cookieJar.type, {parentId: workspace._id}); + + // Nothing to do here + if (cookieJars.length <= 1) { + return; + } + + const chosenJar = cookieJars[0]; + for (const cookieJar of cookieJars) { + if (cookieJar._id === chosenJar._id) { + continue; + } + + for (const cookie of cookieJar.cookies) { + if (chosenJar.cookies.find(c => c.id === cookie.id)) { + continue; + } + + chosenJar.cookies.push(cookie); + } + + // Remove unnecessary jar + await remove(cookieJar); + } + + // Update remaining jar + await update(chosenJar); + + console.log(`[fix] Merged ${cookieJars.length} cookie jars under ${workspace.name}`); +} diff --git a/app/ui/import.js b/app/common/import.js similarity index 94% rename from app/ui/import.js rename to app/common/import.js index 8806699cc..9994c18f8 100644 --- a/app/ui/import.js +++ b/app/common/import.js @@ -1,14 +1,14 @@ import {convert} from 'insomnia-importers'; -import * as db from '../common/database'; -import * as har from '../common/har'; +import * as db from './database'; +import * as har from './har'; import * as models from '../models/index'; -import {getAppVersion} from '../common/constants'; -import * as misc from '../common/misc'; -import {showModal} from './components/modals/index'; -import AlertModal from './components/modals/alert-modal'; -import * as fetch from '../common/fetch'; +import {getAppVersion} from './constants'; +import * as misc from './misc'; +import {showModal} from '../ui/components/modals/index'; +import AlertModal from '../ui/components/modals/alert-modal'; +import * as fetch from './fetch'; import fs from 'fs'; -import {trackEvent} from '../common/analytics'; +import {trackEvent} from './analytics'; const EXPORT_FORMAT = 3; @@ -107,7 +107,7 @@ export async function importRaw (workspace, rawContent, generateNewIds = false) for (const resource of data.resources) { // Buffer DB changes // NOTE: Doing it inside here so it's more "scalable" - db.bufferChanges(100); + await db.bufferChanges(100); // Replace null parentIds with current workspace if (!resource.parentId) { @@ -147,7 +147,7 @@ export async function importRaw (workspace, rawContent, generateNewIds = false) importedDocs[newDoc.type].push(newDoc); } - db.flushChanges(); + await db.flushChanges(); return { source: results.type.id, diff --git a/app/models/__tests__/workspace.test.js b/app/models/__tests__/workspace.test.js index cbdcf7606..85b740375 100644 --- a/app/models/__tests__/workspace.test.js +++ b/app/models/__tests__/workspace.test.js @@ -25,25 +25,27 @@ describe('migrate()', () => { expect(certs.length).toBe(2); expect(certs.sort((c1, c2) => c1._id > c2._id ? -1 : 1)).toEqual([{ - _id: 'crt_a262d22b5fa8491c9bd958fba03e301e', - cert: null, - disabled: false, - isPrivate: false, - key: 'key', - parentId: 'wrk_cc1dd2ca4275747aa88199e8efd42403', - passphrase: 'mypass', - pfx: null, - type: 'ClientCertificate' - }, { - _id: 'crt_2e7c268809ee44b8900d5cbbaa7d3a19', + _id: 'crt_e3e96e5fdd6842298b66dee1f0940f3d', cert: 'cert', disabled: false, isPrivate: false, + host: '', key: null, parentId: 'wrk_cc1dd2ca4275747aa88199e8efd42403', passphrase: null, pfx: null, type: 'ClientCertificate' + }, { + _id: 'crt_dd2ccc1a2745477a881a9e8ef9d42403', + cert: null, + disabled: false, + isPrivate: false, + host: '', + key: 'key', + parentId: 'wrk_cc1dd2ca4275747aa88199e8efd42403', + passphrase: 'mypass', + pfx: null, + type: 'ClientCertificate' }]); expect(migratedWorkspace.certificates).toBeUndefined(); diff --git a/app/models/workspace.js b/app/models/workspace.js index f5aedf9ef..b0f32cf1b 100644 --- a/app/models/workspace.js +++ b/app/models/workspace.js @@ -30,10 +30,7 @@ export async function migrate (doc: Workspace): Promise { process.nextTick(() => update(doc, {parentId: null})); } - await _ensureDependencies(doc); - doc = await _migrateExtractClientCertificates(doc); - - return doc; + return _migrateExtractClientCertificates(doc); } export function getById (id: string): Promise { @@ -41,9 +38,7 @@ export function getById (id: string): Promise { } export async function create (patch: Object = {}): Promise { - const doc = await db.docCreate(type, patch); - await _ensureDependencies(doc); - return doc; + return db.docCreate(type, patch); } export async function all (): Promise> { @@ -69,11 +64,6 @@ export function remove (workspace: Workspace): Promise { return db.remove(workspace); } -async function _ensureDependencies (workspace: Workspace) { - await models.cookieJar.getOrCreateForParentId(workspace._id); - await models.environment.getOrCreateForWorkspaceId(workspace._id); -} - async function _migrateExtractClientCertificates (workspace: Workspace): Promise { const certificates = (workspace: Object).certificates || null; if (!Array.isArray(certificates)) { @@ -84,7 +74,7 @@ async function _migrateExtractClientCertificates (workspace: Workspace): Promise for (const cert of certificates) { await models.clientCertificate.create({ parentId: workspace._id, - host: cert.host, + host: cert.host || '', passphrase: cert.passphrase || null, cert: cert.cert || null, key: cert.key || null, diff --git a/app/sync/__tests__/sync.test.js b/app/sync/__tests__/sync.test.js index 2224406e1..c17ffa005 100644 --- a/app/sync/__tests__/sync.test.js +++ b/app/sync/__tests__/sync.test.js @@ -257,8 +257,8 @@ describe('Integration tests for creating Resources and pushing', () => { // Assert that all our new models were created expect((await models.workspace.all()).length).toBe(2); expect((await models.request.all()).length).toBe(3); - expect((await models.environment.all()).length).toBe(3); - expect((await models.cookieJar.all()).length).toBe(2); + expect((await models.environment.all()).length).toBe(1); + expect((await models.cookieJar.all()).length).toBe(0); // Assert that initializing sync will create the initial resources expect((await syncStorage.allConfigs()).length).toBe(0); @@ -267,7 +267,7 @@ describe('Integration tests for creating Resources and pushing', () => { jest.runOnlyPendingTimers(); await promise; expect((await syncStorage.allConfigs()).length).toBe(2); - expect((await syncStorage.allResources()).length).toBe(9); + expect((await syncStorage.allResources()).length).toBe(5); // Mark all configs as auto sync const configs = await syncStorage.allConfigs(); @@ -286,7 +286,7 @@ describe('Integration tests for creating Resources and pushing', () => { it('Resources created on DB change', async () => { // Fetch the workspace and create a new request - db.bufferChanges(); + await db.bufferChanges(); await models.request.create({ _id: 'req_t', url: 'https://google.com', @@ -302,19 +302,19 @@ describe('Integration tests for creating Resources and pushing', () => { // Assert expect((await syncStorage.allConfigs()).length).toBe(2); - expect((await syncStorage.allResources()).length).toBe(10); + expect((await syncStorage.allResources()).length).toBe(6); expect(_decryptResource(resource).url).toBe('https://google.com'); expect(resource.removed).toBe(false); expect(session.syncPush.mock.calls.length).toBe(1); - expect(session.syncPush.mock.calls[0][0].length).toBe(10); + expect(session.syncPush.mock.calls[0][0].length).toBe(6); expect(session.syncPull.mock.calls).toEqual([]); }); it('Resources revived on DB change', async () => { // Fetch the workspace and create a new request - db.bufferChanges(); + await db.bufferChanges(); const request = await models.request.create({ _id: 'req_t', name: 'Original Request', @@ -332,7 +332,7 @@ describe('Integration tests for creating Resources and pushing', () => { ); // Update it and push it again - db.bufferChanges(); + await db.bufferChanges(); await models.request.update(request, {name: 'New Name'}); await db.flushChanges(); await sync.writePendingChanges(); @@ -349,7 +349,7 @@ describe('Integration tests for creating Resources and pushing', () => { // Create, update a request, and fetch it's resource const request = await models.request.getById('req_1'); const resource = await syncStorage.getResourceByDocId(request._id); - db.bufferChanges(); + await db.bufferChanges(); const updatedRequest = await models.request.update(request, {name: 'New Name'}); // Drain and fetch new resource @@ -366,7 +366,7 @@ describe('Integration tests for creating Resources and pushing', () => { expect(resource.removed).toBe(false); expect(session.syncPush.mock.calls.length).toBe(1); - expect(session.syncPush.mock.calls[0][0].length).toBe(9); + expect(session.syncPush.mock.calls[0][0].length).toBe(5); expect(session.syncPull.mock.calls).toEqual([]); }); @@ -375,7 +375,7 @@ describe('Integration tests for creating Resources and pushing', () => { // Create, update a request, and fetch it's resource const request = await models.request.getById('req_1'); const resource = await syncStorage.getResourceByDocId(request._id); - db.bufferChanges(); + await db.bufferChanges(); await models.request.remove(request); // Drain and fetch new resource @@ -389,7 +389,7 @@ describe('Integration tests for creating Resources and pushing', () => { expect(updatedResource.removed).toBe(true); expect(session.syncPush.mock.calls.length).toBe(1); - expect(session.syncPush.mock.calls[0][0].length).toBe(9); + expect(session.syncPush.mock.calls[0][0].length).toBe(5); expect(session.syncPull.mock.calls).toEqual([]); }); diff --git a/app/sync/index.js b/app/sync/index.js index 22fc00734..1ec3b9dd1 100644 --- a/app/sync/index.js +++ b/app/sync/index.js @@ -248,7 +248,7 @@ export async function push (resourceGroupId = null) { } // Resolve conflicts - db.bufferChanges(); + await db.bufferChanges(); for (const serverResource of conflicts) { const localResource = await store.getResourceByDocId( serverResource.id, @@ -283,7 +283,7 @@ export async function push (resourceGroupId = null) { } } - db.flushChanges(); + db.flushChangesAsync(); } export async function pull (resourceGroupId = null, createMissingResources = true) { @@ -347,7 +347,7 @@ export async function pull (resourceGroupId = null, createMissingResources = tru // Insert all the created docs to the DB // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - db.bufferChanges(); + await db.bufferChanges(); for (const serverResource of createdResources) { let doc; @@ -390,13 +390,13 @@ export async function pull (resourceGroupId = null, createMissingResources = tru logger.debug(`Pull created ${createdResources.length} resources`); } - db.flushChanges(); + db.flushChangesAsync(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Save all the updated docs to the DB // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - db.bufferChanges(); + await db.bufferChanges(); for (const serverResource of updatedResources) { try { const {resourceGroupId, encContent} = serverResource; @@ -416,7 +416,7 @@ export async function pull (resourceGroupId = null, createMissingResources = tru logger.warn('Failed to decode updated resource', e, serverResource); } } - db.flushChanges(); + db.flushChangesAsync(); if (updatedResources.length) { logger.debug(`Pull updated ${updatedResources.length} resources`); @@ -426,7 +426,7 @@ export async function pull (resourceGroupId = null, createMissingResources = tru // Remove all the docs that need removing // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - db.bufferChanges(); + await db.bufferChanges(); for (const id of idsToRemove) { const resource = await store.getResourceByDocId(id); if (!resource) { @@ -444,7 +444,7 @@ export async function pull (resourceGroupId = null, createMissingResources = tru // Remove from DB await db.remove(doc, true); } - db.flushChanges(); + db.flushChangesAsync(); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // Push all the docs that need pushing // diff --git a/app/sync/session.js b/app/sync/session.js index ea6bc9acd..6d9665596 100644 --- a/app/sync/session.js +++ b/app/sync/session.js @@ -154,7 +154,7 @@ export function getPrivateKey () { } export function getCurrentSessionId () { - if (window) { + if (global.window) { // NOTE: Must check for window on global return window.localStorage.getItem('currentSessionId'); } else { return false; diff --git a/app/ui/containers/app.js b/app/ui/containers/app.js index 7215db115..410b0f946 100644 --- a/app/ui/containers/app.js +++ b/app/ui/containers/app.js @@ -56,6 +56,8 @@ class App extends PureComponent { paneHeight: props.paneHeight || DEFAULT_PANE_HEIGHT }; + this._isMigratingChildren = false; + this._getRenderContextPromiseCache = {}; this._savePaneWidth = debounce(paneWidth => this._updateActiveWorkspaceMeta({paneWidth})); @@ -778,7 +780,54 @@ class App extends PureComponent { document.removeEventListener('mousemove', this._handleMouseMove); } + async _ensureWorkspaceChildren (props) { + const {activeWorkspace, activeCookieJar, environments} = props; + const baseEnvironments = environments.filter(e => e.parentId === activeWorkspace._id); + + // Nothing to do + if (baseEnvironments.length && activeCookieJar) { + return; + } + + // We already started migrating. Let it finish. + if (this._isMigratingChildren) { + return; + } + + // Prevent rendering of everything + this._isMigratingChildren = true; + + await db.bufferChanges(); + if (baseEnvironments.length === 0) { + await models.environment.create({parentId: activeWorkspace._id}); + console.log(`[app] Created missing base environment for ${activeWorkspace.name}`); + } + + if (!activeCookieJar) { + await models.cookieJar.create({parentId: this.props.activeWorkspace._id}); + console.log(`[app] Created missing cookie jar for ${activeWorkspace.name}`); + } + + await db.flushChanges(); + + // Flush "transaction" + this._isMigratingChildren = false; + } + + componentWillReceiveProps (nextProps) { + this._ensureWorkspaceChildren(nextProps); + } + + componentWillMount () { + this._ensureWorkspaceChildren(this.props); + } + render () { + if (this._isMigratingChildren) { + console.log('[app] Waiting for migration to complete'); + return null; + } + return (
@@ -1015,7 +1064,7 @@ async function _moveDoc (docToMove, parentId, targetId, targetOffset) { // anyway console.log(`[app] Recreating Sort Keys ${beforeKey} ${afterKey}`); - db.bufferChanges(300); + await db.bufferChanges(300); docs.map((r, i) => __updateDoc(r, {metaSortKey: i * 100, parentId})); } else { const metaSortKey = afterKey - ((afterKey - beforeKey) / 2); diff --git a/app/ui/redux/modules/global.js b/app/ui/redux/modules/global.js index 95e409f66..c67763bdf 100644 --- a/app/ui/redux/modules/global.js +++ b/app/ui/redux/modules/global.js @@ -6,7 +6,7 @@ import path from 'path'; import AskModal from '../../../ui/components/modals/ask-modal'; import * as moment from 'moment'; -import * as importUtils from '../../import'; +import * as importUtils from '../../../common/import'; import {trackEvent} from '../../../common/analytics'; import AlertModal from '../../components/modals/alert-modal'; import PaymentNotificationModal from '../../components/modals/payment-notification-modal'; diff --git a/package-lock.json b/package-lock.json index 57a5161c3..1ed08df9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -438,6 +438,12 @@ "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.8.15.tgz", "integrity": "sha1-ju8IJ/BN/w7IhXupJavj/qYZTlI=" }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, "async": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", @@ -4740,6 +4746,31 @@ "integrity": "sha512-kkjwkMqj0h4w/sb32ERCDxCQkREMCAgS39DscDnSwDsbxnwwM1BTZySdC3Bn1lhY7vL08n9GoO/fVTynjDgRyQ==", "dev": true }, + "expect": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-21.2.1.tgz", + "integrity": "sha512-orfQQqFRTX0jH7znRIGi8ZMR8kTNpXklTTz8+HGTpmTKZo3Occ6JNB5FXMb8cRuiiC/GyDqsr30zUa66ACYlYw==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "jest-diff": "21.2.1", + "jest-get-type": "21.2.0", + "jest-matcher-utils": "21.2.1", + "jest-message-util": "21.2.1", + "jest-regex-util": "21.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + } + } + }, "express": { "version": "4.16.2", "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", @@ -8029,364 +8060,1017 @@ "integrity": "sha512-Cu/kb+4HiNSejAPhSaN1VukdNTTi/r4/e+yykqjlG/IW+1gZH5b4+Bq3whDX4tvbYugta3r8KTMUiqT3fIGxuQ==" }, "jest": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest/-/jest-19.0.2.tgz", - "integrity": "sha1-t5T6r4/0Yec4jyi+71WaVPILLBA=", + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-21.2.1.tgz", + "integrity": "sha512-mXN0ppPvWYoIcC+R+ctKxAJ28xkt/Z5Js875padm4GbgUn6baeR5N4Ng6LjatIRpUQDZVJABT7Y4gucFjPryfw==", "dev": true, "requires": { - "jest-cli": "19.0.2" + "jest-cli": "21.2.1" }, "dependencies": { - "callsites": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "ansi-escapes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", + "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", "dev": true }, - "camelcase": { + "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "jest-cli": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-19.0.2.tgz", - "integrity": "sha1-zDYgtirKxfLZOlSMtu9pfU7IVEM=", + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-21.2.1.tgz", + "integrity": "sha512-T1BzrbFxDIW/LLYQqVfo94y/hhaj1NzVQkZgBumAC+sxbjMROI7VkihOdxNR758iYbQykL2ZOWUBurFgkQrzdg==", "dev": true, "requires": { - "ansi-escapes": "1.4.0", - "callsites": "2.0.0", - "chalk": "1.1.3", + "ansi-escapes": "3.0.0", + "chalk": "2.3.0", + "glob": "7.1.2", "graceful-fs": "4.1.11", "is-ci": "1.0.10", "istanbul-api": "1.2.1", "istanbul-lib-coverage": "1.1.1", "istanbul-lib-instrument": "1.9.1", - "jest-changed-files": "19.0.2", - "jest-config": "19.0.4", - "jest-environment-jsdom": "19.0.2", - "jest-haste-map": "19.0.2", - "jest-jasmine2": "19.0.2", - "jest-message-util": "19.0.0", - "jest-regex-util": "19.0.0", - "jest-resolve-dependencies": "19.0.0", - "jest-runtime": "19.0.4", - "jest-snapshot": "19.0.2", - "jest-util": "19.0.2", + "istanbul-lib-source-maps": "1.2.2", + "jest-changed-files": "21.2.0", + "jest-config": "21.2.1", + "jest-environment-jsdom": "21.2.1", + "jest-haste-map": "21.2.0", + "jest-message-util": "21.2.1", + "jest-regex-util": "21.2.0", + "jest-resolve-dependencies": "21.2.0", + "jest-runner": "21.2.1", + "jest-runtime": "21.2.1", + "jest-snapshot": "21.2.1", + "jest-util": "21.2.1", "micromatch": "2.3.11", "node-notifier": "5.1.2", + "pify": "3.0.0", "slash": "1.0.0", - "string-length": "1.0.1", - "throat": "3.2.0", + "string-length": "2.0.0", + "strip-ansi": "4.0.0", "which": "1.3.0", "worker-farm": "1.5.2", - "yargs": "6.6.0" + "yargs": "9.0.1" } }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, - "yargs": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", - "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "camelcase": "3.0.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "y18n": "3.2.1", - "yargs-parser": "4.2.1" + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } } }, - "yargs-parser": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", - "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { - "camelcase": "3.0.0" + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" } - } - } - }, - "jest-changed-files": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-19.0.2.tgz", - "integrity": "sha1-FsVMhMMnC+QI4G0uivPz43qIWCQ=", - "dev": true - }, - "jest-config": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-19.0.4.tgz", - "integrity": "sha1-QpgCEdRkF+kcp6v/0IbCcCNPc/0=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "jest-environment-jsdom": "19.0.2", - "jest-environment-node": "19.0.2", - "jest-jasmine2": "19.0.2", - "jest-regex-util": "19.0.0", - "jest-resolve": "19.0.2", - "jest-validate": "19.0.2", - "pretty-format": "19.0.0" - } - }, - "jest-diff": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-19.0.0.tgz", - "integrity": "sha1-0VY8/FbItgIymI+8BdTRbtkPBjw=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "diff": "3.4.0", - "jest-matcher-utils": "19.0.0", - "pretty-format": "19.0.0" - } - }, - "jest-environment-jsdom": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-19.0.2.tgz", - "integrity": "sha1-ztqFnEpLlKs15N59q1S5JvKT5KM=", - "dev": true, - "requires": { - "jest-mock": "19.0.0", - "jest-util": "19.0.2", - "jsdom": "9.12.0" - } - }, - "jest-environment-node": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-19.0.2.tgz", - "integrity": "sha1-boQHnbh+0h0MBeH5Zp8gexFv6Zs=", - "dev": true, - "requires": { - "jest-mock": "19.0.0", - "jest-util": "19.0.2" - } - }, - "jest-file-exists": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jest-file-exists/-/jest-file-exists-19.0.0.tgz", - "integrity": "sha1-zKLlh6EeyS4kz+qz+KlNZX8/zrg=", - "dev": true - }, - "jest-haste-map": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-19.0.2.tgz", - "integrity": "sha1-KGSEw6Fuhtp4crCHfDXc4ww9bwc=", - "dev": true, - "requires": { - "fb-watchman": "2.0.0", - "graceful-fs": "4.1.11", - "micromatch": "2.3.11", - "sane": "1.5.0", - "worker-farm": "1.5.2" - } - }, - "jest-jasmine2": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-19.0.2.tgz", - "integrity": "sha1-FnmRrIJZgfsagArxJug6/MqDLHM=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "jest-matcher-utils": "19.0.0", - "jest-matchers": "19.0.0", - "jest-message-util": "19.0.0", - "jest-snapshot": "19.0.2" - } - }, - "jest-matcher-utils": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-19.0.0.tgz", - "integrity": "sha1-Xs2bY1ZdKwAfYfv37Ex/U3lkVk0=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "pretty-format": "19.0.0" - } - }, - "jest-matchers": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jest-matchers/-/jest-matchers-19.0.0.tgz", - "integrity": "sha1-x07Mbr/sBvOEdnuk1vpKQtZ1V1Q=", - "dev": true, - "requires": { - "jest-diff": "19.0.0", - "jest-matcher-utils": "19.0.0", - "jest-message-util": "19.0.0", - "jest-regex-util": "19.0.0" - } - }, - "jest-message-util": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-19.0.0.tgz", - "integrity": "sha1-cheWuJwOTXYWBvm6jLgoo7YkZBY=", - "dev": true, - "requires": { - "chalk": "1.1.3", - "micromatch": "2.3.11" - } - }, - "jest-mock": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-19.0.0.tgz", - "integrity": "sha1-ZwOGQelgerLOCOxKjLg6q7yJnQE=", - "dev": true - }, - "jest-regex-util": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-19.0.0.tgz", - "integrity": "sha1-t3VFhxEq7eFFZRC7H2r+dO9ZhpE=", - "dev": true - }, - "jest-resolve": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-19.0.2.tgz", - "integrity": "sha1-V5NXXeTweuwy99f/DGwYGWPu+zw=", - "dev": true, - "requires": { - "browser-resolve": "1.11.2", - "jest-haste-map": "19.0.2", - "resolve": "1.5.0" - } - }, - "jest-resolve-dependencies": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-19.0.0.tgz", - "integrity": "sha1-p0GtH6CUFA5k7PJkKlBPg07OIu4=", - "dev": true, - "requires": { - "jest-file-exists": "19.0.0" - } - }, - "jest-runtime": { - "version": "19.0.4", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-19.0.4.tgz", - "integrity": "sha1-8WfZ8TR3UvICc2EGeSZIU0n8wkU=", - "dev": true, - "requires": { - "babel-core": "6.26.0", - "babel-jest": "19.0.0", - "babel-plugin-istanbul": "4.1.5", - "chalk": "1.1.3", - "graceful-fs": "4.1.11", - "jest-config": "19.0.4", - "jest-file-exists": "19.0.0", - "jest-haste-map": "19.0.2", - "jest-regex-util": "19.0.0", - "jest-resolve": "19.0.2", - "jest-util": "19.0.2", - "json-stable-stringify": "1.0.1", - "micromatch": "2.3.11", - "strip-bom": "3.0.0", - "yargs": "6.6.0" - }, - "dependencies": { - "camelcase": { + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, - "yargs": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", - "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", "dev": true, "requires": { - "camelcase": "3.0.0", + "has-flag": "2.0.0" + } + }, + "yargs": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz", + "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", + "dev": true, + "requires": { + "camelcase": "4.1.0", "cliui": "3.2.0", "decamelize": "1.2.0", "get-caller-file": "1.0.2", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", "require-directory": "2.1.1", "require-main-filename": "1.0.1", "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", "y18n": "3.2.1", - "yargs-parser": "4.2.1" + "yargs-parser": "7.0.0" } }, "yargs-parser": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", - "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", "dev": true, "requires": { - "camelcase": "3.0.0" + "camelcase": "4.1.0" + } + } + } + }, + "jest-changed-files": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-21.2.0.tgz", + "integrity": "sha512-+lCNP1IZLwN1NOIvBcV5zEL6GENK6TXrDj4UxWIeLvIsIDa+gf6J7hkqsW2qVVt/wvH65rVvcPwqXdps5eclTQ==", + "dev": true, + "requires": { + "throat": "4.1.0" + } + }, + "jest-config": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-21.2.1.tgz", + "integrity": "sha512-fJru5HtlD/5l2o25eY9xT0doK3t2dlglrqoGpbktduyoI0T5CwuB++2YfoNZCrgZipTwPuAGonYv0q7+8yDc/A==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "glob": "7.1.2", + "jest-environment-jsdom": "21.2.1", + "jest-environment-node": "21.2.1", + "jest-get-type": "21.2.0", + "jest-jasmine2": "21.2.1", + "jest-regex-util": "21.2.0", + "jest-resolve": "21.2.0", + "jest-util": "21.2.1", + "jest-validate": "21.2.1", + "pretty-format": "21.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "jest-diff": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-21.2.1.tgz", + "integrity": "sha512-E5fu6r7PvvPr5qAWE1RaUwIh/k6Zx/3OOkZ4rk5dBJkEWRrUuSgbMt2EO8IUTPTd6DOqU3LW6uTIwX5FRvXoFA==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "diff": "3.4.0", + "jest-get-type": "21.2.0", + "pretty-format": "21.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "jest-docblock": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz", + "integrity": "sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw==", + "dev": true + }, + "jest-environment-jsdom": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-21.2.1.tgz", + "integrity": "sha512-mecaeNh0eWmzNrUNMWARysc0E9R96UPBamNiOCYL28k7mksb1d0q6DD38WKP7ABffjnXyUWJPVaWRgUOivwXwg==", + "dev": true, + "requires": { + "jest-mock": "21.2.0", + "jest-util": "21.2.1", + "jsdom": "9.12.0" + } + }, + "jest-environment-node": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-21.2.1.tgz", + "integrity": "sha512-R211867wx9mVBVHzrjGRGTy5cd05K7eqzQl/WyZixR/VkJ4FayS8qkKXZyYnwZi6Rxo6WEV81cDbiUx/GfuLNw==", + "dev": true, + "requires": { + "jest-mock": "21.2.0", + "jest-util": "21.2.1" + } + }, + "jest-get-type": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-21.2.0.tgz", + "integrity": "sha512-y2fFw3C+D0yjNSDp7ab1kcd6NUYfy3waPTlD8yWkAtiocJdBRQqNoRqVfMNxgj+IjT0V5cBIHJO0z9vuSSZ43Q==", + "dev": true + }, + "jest-haste-map": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-21.2.0.tgz", + "integrity": "sha512-5LhsY/loPH7wwOFRMs+PT4aIAORJ2qwgbpMFlbWbxfN0bk3ZCwxJ530vrbSiTstMkYLao6JwBkLhCJ5XbY7ZHw==", + "dev": true, + "requires": { + "fb-watchman": "2.0.0", + "graceful-fs": "4.1.11", + "jest-docblock": "21.2.0", + "micromatch": "2.3.11", + "sane": "2.2.0", + "worker-farm": "1.5.2" + } + }, + "jest-jasmine2": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-21.2.1.tgz", + "integrity": "sha512-lw8FXXIEekD+jYNlStfgNsUHpfMWhWWCgHV7n0B7mA/vendH7vBFs8xybjQsDzJSduptBZJHqQX9SMssya9+3A==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "expect": "21.2.1", + "graceful-fs": "4.1.11", + "jest-diff": "21.2.1", + "jest-matcher-utils": "21.2.1", + "jest-message-util": "21.2.1", + "jest-snapshot": "21.2.1", + "p-cancelable": "0.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "jest-matcher-utils": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-21.2.1.tgz", + "integrity": "sha512-kn56My+sekD43dwQPrXBl9Zn9tAqwoy25xxe7/iY4u+mG8P3ALj5IK7MLHZ4Mi3xW7uWVCjGY8cm4PqgbsqMCg==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "jest-get-type": "21.2.0", + "pretty-format": "21.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "jest-message-util": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-21.2.1.tgz", + "integrity": "sha512-EbC1X2n0t9IdeMECJn2BOg7buOGivCvVNjqKMXTzQOu7uIfLml+keUfCALDh8o4rbtndIeyGU8/BKfoTr/LVDQ==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "micromatch": "2.3.11", + "slash": "1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "jest-mock": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-21.2.0.tgz", + "integrity": "sha512-aZDfyVf0LEoABWiY6N0d+O963dUQSyUa4qgzurHR3TBDPen0YxKCJ6l2i7lQGh1tVdsuvdrCZ4qPj+A7PievCw==", + "dev": true + }, + "jest-regex-util": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-21.2.0.tgz", + "integrity": "sha512-BKQ1F83EQy0d9Jen/mcVX7D+lUt2tthhK/2gDWRgLDJRNOdRgSp1iVqFxP8EN1ARuypvDflRfPzYT8fQnoBQFQ==", + "dev": true + }, + "jest-resolve": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-21.2.0.tgz", + "integrity": "sha512-vefQ/Lr+VdNvHUZFQXWtOqHX3HEdOc2MtSahBO89qXywEbUxGPB9ZLP9+BHinkxb60UT2Q/tTDOS6rYc6Mwigw==", + "dev": true, + "requires": { + "browser-resolve": "1.11.2", + "chalk": "2.3.0", + "is-builtin-module": "1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-21.2.0.tgz", + "integrity": "sha512-ok8ybRFU5ScaAcfufIQrCbdNJSRZ85mkxJ1EhUp8Bhav1W1/jv/rl1Q6QoVQHObNxmKnbHVKrfLZbCbOsXQ+bQ==", + "dev": true, + "requires": { + "jest-regex-util": "21.2.0" + } + }, + "jest-runner": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-21.2.1.tgz", + "integrity": "sha512-Anb72BOQlHqF/zETqZ2K20dbYsnqW/nZO7jV8BYENl+3c44JhMrA8zd1lt52+N7ErnsQMd2HHKiVwN9GYSXmrg==", + "dev": true, + "requires": { + "jest-config": "21.2.1", + "jest-docblock": "21.2.0", + "jest-haste-map": "21.2.0", + "jest-jasmine2": "21.2.1", + "jest-message-util": "21.2.1", + "jest-runtime": "21.2.1", + "jest-util": "21.2.1", + "pify": "3.0.0", + "throat": "4.1.0", + "worker-farm": "1.5.2" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "jest-runtime": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-21.2.1.tgz", + "integrity": "sha512-6omlpA3+NSE+rHwD0PQjNEjZeb2z+oRmuehMfM1tWQVum+E0WV3pFt26Am0DUfQkkPyTABvxITRjCUclYgSOsA==", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "babel-jest": "21.2.0", + "babel-plugin-istanbul": "4.1.5", + "chalk": "2.3.0", + "convert-source-map": "1.5.0", + "graceful-fs": "4.1.11", + "jest-config": "21.2.1", + "jest-haste-map": "21.2.0", + "jest-regex-util": "21.2.0", + "jest-resolve": "21.2.0", + "jest-util": "21.2.1", + "json-stable-stringify": "1.0.1", + "micromatch": "2.3.11", + "slash": "1.0.0", + "strip-bom": "3.0.0", + "write-file-atomic": "2.3.0", + "yargs": "9.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "babel-jest": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-21.2.0.tgz", + "integrity": "sha512-O0W2qLoWu1QOoOGgxiR2JID4O6WSpxPiQanrkyi9SSlM0PJ60Ptzlck47lhtnr9YZO3zYOsxHwnyeWJ6AffoBQ==", + "dev": true, + "requires": { + "babel-plugin-istanbul": "4.1.5", + "babel-preset-jest": "21.2.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-21.2.0.tgz", + "integrity": "sha512-yi5QuiVyyvhBUDLP4ButAnhYzkdrUwWDtvUJv71hjH3fclhnZg4HkDeqaitcR2dZZx/E67kGkRcPVjtVu+SJfQ==", + "dev": true + }, + "babel-preset-jest": { + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-21.2.0.tgz", + "integrity": "sha512-hm9cBnr2h3J7yXoTtAVV0zg+3vg0Q/gT2GYuzlreTU0EPkJRtlNgKJJ3tBKEn0+VjAi3JykV6xCJkuUYttEEfA==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "21.2.0", + "babel-plugin-syntax-object-rest-spread": "6.13.0" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + }, + "yargs": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-9.0.1.tgz", + "integrity": "sha1-UqzCP+7Kw0BCB47njAwAf1CF20w=", + "dev": true, + "requires": { + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "4.1.0" } } } }, "jest-snapshot": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-19.0.2.tgz", - "integrity": "sha1-nBshYhT3GHw4v9XHCx76sWsP9Qs=", + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-21.2.1.tgz", + "integrity": "sha512-bpaeBnDpdqaRTzN8tWg0DqOTo2DvD3StOemxn67CUd1p1Po+BUpvePAp44jdJ7Pxcjfg+42o4NHw1SxdCA2rvg==", "dev": true, "requires": { - "chalk": "1.1.3", - "jest-diff": "19.0.0", - "jest-file-exists": "19.0.0", - "jest-matcher-utils": "19.0.0", - "jest-util": "19.0.2", + "chalk": "2.3.0", + "jest-diff": "21.2.1", + "jest-matcher-utils": "21.2.1", + "mkdirp": "0.5.1", "natural-compare": "1.4.0", - "pretty-format": "19.0.0" + "pretty-format": "21.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, "jest-util": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-19.0.2.tgz", - "integrity": "sha1-4KAjKiq55rK1Nmi9s1NMK1l37UE=", + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-21.2.1.tgz", + "integrity": "sha512-r20W91rmHY3fnCoO7aOAlyfC51x2yeV3xF+prGsJAUsYhKeV670ZB8NO88Lwm7ASu8SdH0S+U+eFf498kjhA4g==", "dev": true, "requires": { - "chalk": "1.1.3", + "callsites": "2.0.0", + "chalk": "2.3.0", "graceful-fs": "4.1.11", - "jest-file-exists": "19.0.0", - "jest-message-util": "19.0.0", - "jest-mock": "19.0.0", - "jest-validate": "19.0.2", - "leven": "2.1.0", + "jest-message-util": "21.2.1", + "jest-mock": "21.2.0", + "jest-validate": "21.2.1", "mkdirp": "0.5.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, "jest-validate": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-19.0.2.tgz", - "integrity": "sha1-3FNN9fEnjVtj3zKxQkHU2/ckTAw=", + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-21.2.1.tgz", + "integrity": "sha512-k4HLI1rZQjlU+EC682RlQ6oZvLrE5SCh3brseQc24vbZTxzT/k/3urar5QMCVgjadmSO7lECeGdc6YxnM3yEGg==", "dev": true, "requires": { - "chalk": "1.1.3", - "jest-matcher-utils": "19.0.0", + "chalk": "2.3.0", + "jest-get-type": "21.2.0", "leven": "2.1.0", - "pretty-format": "19.0.0" + "pretty-format": "21.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } } }, "jison": { @@ -14065,6 +14749,12 @@ "object-assign": "4.1.1" } }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "dev": true + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -14962,14 +15652,21 @@ } }, "pretty-format": { - "version": "19.0.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-19.0.0.tgz", - "integrity": "sha1-VlMNMqy5ij+khRxOK503tCBoTIQ=", + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-21.2.1.tgz", + "integrity": "sha512-ZdWPGYAnYfcVP8yKA3zFjCn8s4/17TeYH28MXuC8vTp0o21eXjbFGcOAXZEaDaOFJjc3h2qa7HQNHNshhvoh2A==", "dev": true, "requires": { + "ansi-regex": "3.0.0", "ansi-styles": "3.2.0" }, "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, "ansi-styles": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", @@ -15910,38 +16607,21 @@ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, "sane": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-1.5.0.tgz", - "integrity": "sha1-pK3q52TQSGIeyyfV+ez1ExAZOfM=", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-2.2.0.tgz", + "integrity": "sha512-OSJxhHO0CgPUw3lUm3GhfREAfza45smvEI9ozuFrxKG10GHVo0ryW9FK5VYlLvxj0SV7HVKHW0voYJIRu27GWg==", "dev": true, "requires": { "anymatch": "1.3.2", "exec-sh": "0.2.1", - "fb-watchman": "1.9.2", + "fb-watchman": "2.0.0", + "fsevents": "1.1.3", "minimatch": "3.0.4", "minimist": "1.2.0", "walker": "1.0.7", - "watch": "0.10.0" + "watch": "0.18.0" }, "dependencies": { - "bser": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz", - "integrity": "sha1-OBEWlwsqbe6lZG3RXdcnhES1YWk=", - "dev": true, - "requires": { - "node-int64": "0.4.0" - } - }, - "fb-watchman": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-1.9.2.tgz", - "integrity": "sha1-okz0eCf4LTj7Waaa1wt247auc4M=", - "dev": true, - "requires": { - "bser": "1.0.2" - } - }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", @@ -16494,12 +17174,30 @@ "dev": true }, "string-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", - "integrity": "sha1-VpcPscOFWOnnC3KL894mmsRa36w=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", "dev": true, "requires": { - "strip-ansi": "3.0.1" + "astral-regex": "1.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } } }, "string-width": { @@ -16772,9 +17470,9 @@ "dev": true }, "throat": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-3.2.0.tgz", - "integrity": "sha512-/EY8VpvlqJ+sFtLPeOgc8Pl7kQVOWv0woD87KTXVHPIAE842FGT+rokxIhe8xIUP1cfgrkt0as0vDLjDiMtr8w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", "dev": true }, "throttleit": { @@ -17355,10 +18053,22 @@ } }, "watch": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz", - "integrity": "sha1-d3mLLaD5kQ1ZXxrOWwwiWFIfIdw=", - "dev": true + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/watch/-/watch-0.18.0.tgz", + "integrity": "sha1-KAlUdsbffJDJYxOJkMClQj60uYY=", + "dev": true, + "requires": { + "exec-sh": "0.2.1", + "minimist": "1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } }, "watchpack": { "version": "1.4.0", diff --git a/package.json b/package.json index cd6594374..d2eeada50 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,7 @@ "eslint-plugin-standard": "^3.0.1", "file-loader": "^1.1.5", "flow-bin": "^0.58.0", - "jest": "^19.0.2", + "jest": "^21.2.1", "less": "^2.7.2", "less-loader": "^4.0.5", "ncp": "^2.0.0",