diff --git a/.bowerrc b/.bowerrc deleted file mode 100644 index daf40834..00000000 --- a/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "lib" -} diff --git a/.eslintrc b/.eslintrc index d6468abe..9e39b273 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,6 +1,3 @@ { - "extends": ["gooddata"], - "rules": { - "jest/valid-expect": 0 - } + "extends": ["gooddata"] } diff --git a/Gruntfile.js b/Gruntfile.js index 7f9bd03d..678465fb 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -10,20 +10,6 @@ module.exports = (grunt) => { license: grunt.file.read('tools/license.tmpl'), - eslint: { - options: { - config: '.eslintrc', - format: grunt.option('ci') && 'checkstyle', - outputFile: grunt.option('ci') && 'ci/results/eslint-results.xml' - }, - all: { - src: [ - './*.js', - '{src,test,tools}/**/*.js', - '!tools/yuidoc/**/*' - ] - } - }, copy: { examples: { src: 'dist/gooddata.js', @@ -37,6 +23,24 @@ module.exports = (grunt) => { 'run', 'test:ci' ] + }, + eslint: { + cmd: 'yarn', + args: [ + 'validate' + ] + }, + eslintCi: { + cmd: 'yarn', + args: [ + 'validate:ci' + ] + }, + typings: { + cmd: 'yarn', + args: [ + 'test:typings' + ] } }, grizzly: { @@ -125,13 +129,12 @@ module.exports = (grunt) => { grunt.loadNpmTasks('grunt-grizzly'); grunt.loadNpmTasks('grunt-contrib-yuidoc'); grunt.loadNpmTasks('grunt-gh-pages'); - grunt.loadNpmTasks('gruntify-eslint'); grunt.loadNpmTasks('grunt-run'); grunt.registerTask('default', ['dist']); grunt.registerTask('dist', [ 'getGitInfo', - 'eslint', + 'run:eslint', 'webpack:build-dev', 'webpack:build', 'copy' @@ -139,8 +142,11 @@ module.exports = (grunt) => { grunt.registerTask('bump-gh-pages', ['yuidoc:gh_pages', 'gh-pages-clean', 'gh-pages']); - grunt.registerTask('test', ['eslint', 'run:jest']); + grunt.registerTask('test', [ + 'run:eslintCi', + 'run:jest', + 'run:typings' + ]); grunt.registerTask('dev', ['grizzly', 'watch:js']); grunt.registerTask('doc', ['yuidoc']); - grunt.registerTask('validate', ['eslint']); }; diff --git a/gdc-ci.yaml b/gdc-ci.yaml index a6bc28b2..8c3681b6 100644 --- a/gdc-ci.yaml +++ b/gdc-ci.yaml @@ -1,4 +1,4 @@ # defaults - https://github.com/gooddata/gdc-ci/blob/develop/components/client/gdc-ci.yaml pull-request: - - ci-run-validation - - echo "Running unit tests..." && grunt test + - yarn validate:ci + - grunt test diff --git a/index.d.ts b/index.d.ts index 6ed61263..0b3dc304 100644 --- a/index.d.ts +++ b/index.d.ts @@ -12,18 +12,18 @@ export interface IAccountInfo { profileUri: string; } -export module user { - export function isLoggedIn(): Promise; +export interface IUser { + isLoggedIn(): Promise; - export function login(username: string, password: string): Promise; + login(username: string, password: string): Promise; - export function logout(): Promise; + logout(): Promise; - export function updateProfileSettings(profileId: string, profileSettings: any): Promise; + updateProfileSettings(profileId: string, profileSettings: any): Promise; - export function getAccountInfo(): Promise; + getAccountInfo(): Promise; - export function getFeatureFlags(): Promise; + getFeatureFlags(): Promise; } export interface IIdentifierUriPair { @@ -67,60 +67,60 @@ export interface IValidElementsResponse { } } -export module md { - export function getObjects(projectId: string, objectUris: string[]): Promise; +export interface IMetadata { + getObjects(projectId: string, objectUris: string[]): Promise; - export function getObjectsByQuery(projectId: string, options: { category?: string, mode?: string, author?: string, limit?: number }): Promise; + getObjectsByQuery(projectId: string, options: { category?: string, mode?: string, author?: string, limit?: number }): Promise; - export function getObjectUsing(projectId: string, uri: string, options?: { types?: string[], nearest?: boolean }): T; + getObjectUsing(projectId: string, uri: string, options?: { types?: string[], nearest?: boolean }): T; - export function getObjectUsingMany(projectId: string, uris: string[], options?: { types?: string[], nearest?: boolean }): T; + getObjectUsingMany(projectId: string, uris: string[], options?: { types?: string[], nearest?: boolean }): T; - export function getAttribute(projectId: string): Promise; + getAttribute(projectId: string): Promise; - export function getVisualizations(projectId: string): Promise; + getVisualizations(projectId: string): Promise; - export function getDimensions(projectId: string): Promise; + getDimensions(projectId: string): Promise; - export function getFacts(projectId: string): Promise; + getFacts(projectId: string): Promise; - export function getMetrics(projectId: string): Promise; + getMetrics(projectId: string): Promise; - export function getFolders(projectId: string, type: string): Promise; + getFolders(projectId: string, type: string): Promise; - export function getAvailableMetrics(projectId: string, attributes: string[]): Promise; + getAvailableMetrics(projectId: string, attributes: string[]): Promise; - export function getAvailableAttributes(projectId: string, metrics: string[]): Promise; + getAvailableAttributes(projectId: string, metrics: string[]): Promise; - export function getAvailableFacts(projectId: string, items: string[]): Promise; + getAvailableFacts(projectId: string, items: string[]): Promise; - export function getObjectDetails(uri: string): Promise; + getObjectDetails(uri: string): Promise; - export function getFoldersWithItems(projectId: string, type: string): Promise; + getFoldersWithItems(projectId: string, type: string): Promise; - export function getObjectIdentifier(uri: string): Promise; + getObjectIdentifier(uri: string): Promise; - export function getObjectUri(projectId: string, identifier: string): Promise; + getObjectUri(projectId: string, identifier: string): Promise; - export function getUrisFromIdentifiers(projectId: string, identifiers: string[]): Promise; + getUrisFromIdentifiers(projectId: string, identifiers: string[]): Promise; - export function getIdentifiersFromUris(projectId: string, uris: string[]): Promise; + getIdentifiersFromUris(projectId: string, uris: string[]): Promise; - export function translateElementLabelsToUris(projectId: string, labelUri: string, patterns: string[], mode: 'EXACT' | 'WILD'): Promise + translateElementLabelsToUris(projectId: string, labelUri: string, patterns: string[], mode: 'EXACT' | 'WILD'): Promise - export function getValidElements(projectId: string, id: string, options: IValidElementsOptions): Promise; + getValidElements(projectId: string, id: string, options: IValidElementsOptions): Promise; - export function deleteObject(uri: string): Promise; + deleteObject(uri: string): Promise; - export function createObject(projectId: string, obj: T): Promise; + createObject(projectId: string, obj: T): Promise; - export function ldmManage(projectId: string, maql: string, options: { maxAttempts?: number, pollStep?: number }): Promise; + ldmManage(projectId: string, maql: string, options: { maxAttempts?: number, pollStep?: number }): Promise; - export function etlPull(projectId: string, uploadsDir: string, options: { maxAttempts?: number, pollStep?: number }): Promise; + etlPull(projectId: string, uploadsDir: string, options: { maxAttempts?: number, pollStep?: number }): Promise; } -export module config { - export function setCustomDomain(d: string): void; +export interface IConfig { + setCustomDomain(d: string): void; } export interface ILoadCatalogOptions { @@ -146,10 +146,10 @@ export interface ILoadDateDataSetOptions { returnAllRelatedDateDataSets?: boolean; } -export module catalogue { - export function loadItems(projectId: string, options: ILoadCatalogOptions): Promise; +export interface ICatalogue { + loadItems(projectId: string, options: ILoadCatalogOptions): Promise; - export function loadDateDataSets(projectId: string, options: ILoadDateDataSetOptions): Promise; + loadDateDataSets(projectId: string, options: ILoadDateDataSetOptions): Promise; } export interface ISort { @@ -338,12 +338,12 @@ export interface IVisualizationObject { } } -export module execution { - export function getDataForVis(projectId: string, mdObj: IVisualizationObjectContent, settings: any): Promise; +export interface IExecution { + getDataForVis(projectId: string, mdObj: IVisualizationObjectContent, settings: any): Promise; - export function getData(projectId: string, columns: string[], executionConfiguration: IExecutionConfiguration, settings: any): Promise; + getData(projectId: string, columns: string[], executionConfiguration: IExecutionConfiguration, settings: any): Promise; - export function executeAfm(projectId: string, execution: AFM.IExecution): Promise; + executeAfm(projectId: string, execution: AFM.IExecution): Promise; } export interface IColor { @@ -352,24 +352,24 @@ export interface IColor { b: number; } -export module project { - export function getCurrentProjectId(): Promise; +export interface IProject { + getCurrentProjectId(): Promise; - export function getProjects(profileId: string): Promise; + getProjects(profileId: string): Promise; - export function getDatasets(projectId: string): Promise; + getDatasets(projectId: string): Promise; - export function getColorPalette(projectId: string): Promise; + getColorPalette(projectId: string): Promise; - export function setColorPalette(projectId: string, colors: IColor[]): Promise; + setColorPalette(projectId: string, colors: IColor[]): Promise; - export function getTimezone(projectId: string): Promise; + getTimezone(projectId: string): Promise; - export function setTimezone(projectId: string, timezone: string): Promise; + setTimezone(projectId: string, timezone: string): Promise; - export function createProject(title: string, authorizationToken: string, options?: object): Promise; + createProject(title: string, authorizationToken: string, options?: object): Promise; - export function deleteProject(projectId: string): Promise; + deleteProject(projectId: string): Promise; } export interface IXhrSettings { @@ -377,9 +377,25 @@ export interface IXhrSettings { data?: any; } -export module xhr { - export function get(uri: string, settings?: IXhrSettings): Promise; - export function post(uri: string, settings?: IXhrSettings): Promise; - export function put(uri: string, settings?: IXhrSettings): Promise; - export function ajax(uri: string, settings?: IXhrSettings): Promise; +export interface IXhr { + get(uri: string, settings?: IXhrSettings): Promise; + post(uri: string, settings?: IXhrSettings): Promise; + put(uri: string, settings?: IXhrSettings): Promise; + ajax(uri: string, settings?: IXhrSettings): Promise; } + +export interface ISdk { + xhr: IXhr; + project: IProject; + execution: IExecution; + catalogue: ICatalogue; + config: IConfig; + md: IMetadata; + user: IUser; +} + +export interface ISdkOptions { + domain?: string; +} + +export declare function factory(options?: ISdkOptions): ISdk; diff --git a/package.json b/package.json index d49a2b2b..cd89d6a8 100644 --- a/package.json +++ b/package.json @@ -20,22 +20,31 @@ "build:dist": "rm -rf dist && grunt dist", "prepublish": "npm run build", "test": "jest --watch", + "validate": "eslint --ext .js,.jsx src test", + "validate:ci": "yarn validate -f checkstyle -o ci/results/eslint-results.xml", + "test:typings": "tsc --noEmit index.d.ts", "test:ci": "JEST_JUNIT_OUTPUT=./ci/results/test-results.xml jest --config jest.ci.json" }, "repository": { "type": "git", "url": "git@github.com:gooddata/gooddata-js.git" }, + "jest": { + "transform": { + ".(js|jsx)": "babel-jest" + } + }, "devDependencies": { "async": "2.1.5", "babel-cli": "6.23.0", "babel-core": "6.23.1", + "babel-jest": "22.2.2", "babel-loader": "6.3.2", "babel-plugin-lodash": "3.2.11", "babel-preset-es2015": "6.22.0", "babel-preset-stage-0": "6.22.0", "babel-register": "6.23.0", - "eslint-config-gooddata": "0.0.13", + "eslint-config-gooddata": "0.0.17", "exports-loader": "0.6.3", "fast-levenshtein": "2.0.6", "fetch-mock": "5.12.2", @@ -48,7 +57,6 @@ "grunt-grizzly": "0.12.0", "grunt-run": "0.8.0", "grunt-webpack": "1.0.14", - "gruntify-eslint": "3.1.0", "imports-loader": "0.7.0", "istanbul-instrumenter-loader": "0.2.0", "jest": "21.0.0", @@ -56,6 +64,7 @@ "js-object-pretty-print": "0.2.0", "json-loader": "0.5.4", "lodash-webpack-plugin": "0.11.0", + "typescript": "2.7.2", "webpack": "1.13.2", "webpack-dev-server": "1.16.1" }, diff --git a/src/admin.js b/src/admin.js index 580bf7fd..ea7ca3dd 100644 --- a/src/admin.js +++ b/src/admin.js @@ -1,13 +1,13 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. -import * as dataProducts from './admin/dataProducts'; -import * as domainDataProducts from './admin/domainDataProducts'; -import * as domains from './admin/domains'; -import * as domainSegments from './admin/domainSegments'; -import * as clients from './admin/clients'; -import * as segments from './admin/segments'; -import * as logs from './admin/logs'; -import * as contracts from './admin/contracts'; +import { createModule as dataProductsFactory } from './admin/dataProducts'; +import { createModule as domainDataProductsFactory } from './admin/domainDataProducts'; +import { createModule as domainsFactory } from './admin/domains'; +import { createModule as domainSegmentsFactory } from './admin/domainSegments'; +import { createModule as clientsFactory } from './admin/clients'; +import { createModule as segmentsFactory } from './admin/segments'; +import { createModule as logsFactory } from './admin/logs'; +import { createModule as contractsFactory } from './admin/contracts'; /** * Network-UI support methods. Mostly private @@ -16,14 +16,15 @@ import * as contracts from './admin/contracts'; * @class admin * */ - -export default { - dataProducts, - domainDataProducts, - domains, - domainSegments, - clients, - logs, - contracts, - segments -}; +export function createModule(xhr) { + return { + dataProducts: dataProductsFactory(xhr), + domainDataProducts: domainDataProductsFactory(xhr), + domains: domainsFactory(xhr), + domainSegments: domainSegmentsFactory(xhr), + clients: clientsFactory(xhr), + logs: logsFactory(xhr), + contracts: contractsFactory(xhr), + segments: segmentsFactory(xhr) + }; +} diff --git a/src/admin/clients.js b/src/admin/clients.js index 375bacd6..08978166 100644 --- a/src/admin/clients.js +++ b/src/admin/clients.js @@ -1,4 +1,3 @@ -import { get } from '../xhr'; import * as routes from './routes'; const transformClient = (item) => { @@ -14,37 +13,6 @@ const transformClient = (item) => { }; }; -export const getClient = (contractId, dataProductId, segmentId, domainId, clientId) => { - const query = { stats: 'user' }; - const uri = routes.interpolate( - routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_CLIENT, - { contractId, dataProductId, segmentId, domainId, clientId }, - query - ); - - return get(uri).then(result => transformClient(result)); -}; - -export const getClients = (contractId, dataProductId, segmentId, domainId, filter, paging) => { - const query = filter ? { clientPrefix: filter, stats: 'user' } : { stats: 'user' }; - const uri = paging ? - paging.next : - routes.interpolate( - routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_CLIENTS, - { contractId, dataProductId, segmentId, domainId }, - query - ); - - if (uri) { - return get(uri).then(result => ({ - items: result.clients.items.map(transformClient), - paging: result.clients.paging - })); - } - - return Promise.resolve({ items: [], paging: {} }); -}; - const transformClientUser = (user) => { return { id: user.login, @@ -54,21 +22,60 @@ const transformClientUser = (user) => { }; }; -export const getClientUsers = (contractId, dataProductId, domainId, segmentId, clientId, query, paging) => { - if (paging && !paging.next) { - return Promise.resolve({ items: [], paging: {} }); - } - - const uri = paging ? - paging.next : - routes.interpolate( - routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_CLIENT_USERS, - { contractId, dataProductId, domainId, segmentId, clientId }, +export function createModule(xhr) { + const getClient = (contractId, dataProductId, segmentId, domainId, clientId) => { + const query = { stats: 'user' }; + const uri = routes.interpolate( + routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_CLIENT, + { contractId, dataProductId, segmentId, domainId, clientId }, query ); - return get(uri).then(result => ({ - ...result.clientUsers, - items: result.clientUsers.items.map(transformClientUser) - })); -}; + return xhr.get(uri).then(result => transformClient(result)); + }; + + const getClients = (contractId, dataProductId, segmentId, domainId, filter, paging) => { + const query = filter ? { clientPrefix: filter, stats: 'user' } : { stats: 'user' }; + const uri = paging ? + paging.next : + routes.interpolate( + routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_CLIENTS, + { contractId, dataProductId, segmentId, domainId }, + query + ); + + if (uri) { + return xhr.get(uri).then(result => ({ + items: result.clients.items.map(transformClient), + paging: result.clients.paging + })); + } + + return Promise.resolve({ items: [], paging: {} }); + }; + + const getClientUsers = (contractId, dataProductId, domainId, segmentId, clientId, query, paging) => { + if (paging && !paging.next) { + return Promise.resolve({ items: [], paging: {} }); + } + + const uri = paging ? + paging.next : + routes.interpolate( + routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_CLIENT_USERS, + { contractId, dataProductId, domainId, segmentId, clientId }, + query + ); + + return xhr.get(uri).then(result => ({ + ...result.clientUsers, + items: result.clientUsers.items.map(transformClientUser) + })); + }; + + return { + getClient, + getClients, + getClientUsers + }; +} diff --git a/src/admin/contracts.js b/src/admin/contracts.js index c42d04d9..946cec94 100644 --- a/src/admin/contracts.js +++ b/src/admin/contracts.js @@ -1,7 +1,12 @@ -import { get } from '../xhr'; import * as routes from './routes'; -export const getUserContracts = () => get(routes.CONTRACTS).then(data => ({ - items: data.contracts.items.map(item => item.contract), - paging: data.contracts.paging -})); +export function createModule(xhr) { + const getUserContracts = () => xhr.get(routes.CONTRACTS).then(data => ({ + items: data.contracts.items.map(item => item.contract), + paging: data.contracts.paging + })); + + return { + getUserContracts + }; +} diff --git a/src/admin/dataProducts.js b/src/admin/dataProducts.js index fd39302a..de0faf20 100644 --- a/src/admin/dataProducts.js +++ b/src/admin/dataProducts.js @@ -1,4 +1,3 @@ -import { get, post, del } from '../xhr'; import * as routes from './routes'; import * as segments from './segments'; import * as domainDataProducts from './domainDataProducts'; @@ -22,33 +21,46 @@ export const transformDataProduct = (item) => { return dataProduct; }; -export const getDataProducts = (contractId, include) => - get(routes.interpolate(routes.CONTRACT_DATA_PRODUCTS, { contractId }, include && { include })) - .then(data => ({ - items: data.dataProducts.items.map(transformDataProduct) - })); +export function createModule(xhr) { + const getDataProducts = (contractId, include) => + xhr.get(routes.interpolate(routes.CONTRACT_DATA_PRODUCTS, { contractId }, include && { include })) + .then(data => ({ + items: data.dataProducts.items.map(transformDataProduct) + })); -export const getDataProduct = (contractId, dataProductId, include, stats, state) => - get(routes.interpolate( + const getDataProduct = (contractId, dataProductId, include, stats, state) => + xhr.get(routes.interpolate( routes.CONTRACT_DATA_PRODUCT, { contractId, dataProductId }, Object.assign(include && { include }, stats && { stats }, state && { state }) )) - .then(data => transformDataProduct(data)); - -export const createDataProduct = (contractId, dataProductId, domainIds) => - post(routes.interpolate(routes.CONTRACT_DATA_PRODUCTS, { contractId }), { - data: JSON.stringify({ - dataProductCreate: { - id: dataProductId, - domains: domainIds.map(domainId => routes.interpolate(routes.CONTRACT_DOMAIN, { contractId, domainId })) - } - }) - }); - -export const renameDataProduct = (contractId, dataProductId, newDataProductId) => - post(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_RENAME, { contractId, dataProductId }), { - data: JSON.stringify({ dataProductRename: { id: newDataProductId } }) - }); - -export const deleteDataProduct = (contractId, dataProductId) => - del(routes.interpolate(routes.CONTRACT_DATA_PRODUCT, { contractId, dataProductId })); + .then(data => transformDataProduct(data)); + + const createDataProduct = (contractId, dataProductId, domainIds) => + xhr.post(routes.interpolate(routes.CONTRACT_DATA_PRODUCTS, { contractId }), { + data: JSON.stringify({ + dataProductCreate: { + id: dataProductId, + domains: domainIds.map( + domainId => routes.interpolate(routes.CONTRACT_DOMAIN, { contractId, domainId }) + ) + } + }) + }); + + const renameDataProduct = (contractId, dataProductId, newDataProductId) => + xhr.post(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_RENAME, { contractId, dataProductId }), { + data: JSON.stringify({ dataProductRename: { id: newDataProductId } }) + }); + + const deleteDataProduct = (contractId, dataProductId) => + xhr.del(routes.interpolate(routes.CONTRACT_DATA_PRODUCT, { contractId, dataProductId })); + + return { + getDataProducts, + getDataProduct, + createDataProduct, + renameDataProduct, + deleteDataProduct + }; +} + diff --git a/src/admin/domainDataProducts.js b/src/admin/domainDataProducts.js index 3e94bc65..f9bdd8ed 100644 --- a/src/admin/domainDataProducts.js +++ b/src/admin/domainDataProducts.js @@ -1,7 +1,5 @@ -import { get } from '../xhr'; import * as routes from './routes'; - export const transformDomainDataProduct = ({ domainDataProduct }) => { const { contractId, domainId, dataProductId } = routes.parse(domainDataProduct.links.self, routes.CONTRACT_DATA_PRODUCT_DOMAIN_DATA_PRODUCT); @@ -14,9 +12,15 @@ export const transformDomainDataProduct = ({ domainDataProduct }) => { }; }; -export const getDomainDataProducts = (contractId, dataProductId) => - get(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_DOMAIN_DATA_PRODUCTS, { contractId, dataProductId })) - .then(({ domainDataProducts: { items }, status }) => ({ - items: items.map(transformDomainDataProduct), - status - })); +export function createModule(xhr) { + const getDomainDataProducts = (contractId, dataProductId) => + xhr.get(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_DOMAIN_DATA_PRODUCTS, { contractId, dataProductId })) + .then(({ domainDataProducts: { items }, status }) => ({ + items: items.map(transformDomainDataProduct), + status + })); + + return { + getDomainDataProducts + }; +} diff --git a/src/admin/domainSegments.js b/src/admin/domainSegments.js index d9feb0eb..9227c24c 100644 --- a/src/admin/domainSegments.js +++ b/src/admin/domainSegments.js @@ -1,6 +1,5 @@ -import _ from 'lodash'; +import { omit } from 'lodash'; -import { get, post, put, del } from '../xhr'; import * as routes from './routes'; export const transformDomainSegment = (item) => { @@ -16,84 +15,97 @@ export const transformDomainSegment = (item) => { }; }; -export const getDomainSegments = (contractId, dataProductId, segmentId, query) => { - return get(routes.interpolate( - routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENTS, - { contractId, dataProductId, segmentId }, - query - )) - .then(result => ({ items: result.domainSegments.items.map(transformDomainSegment) })); -}; +export function createModule(xhr) { + const getDomainSegments = (contractId, dataProductId, segmentId, query) => { + return xhr.get(routes.interpolate( + routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENTS, + { contractId, dataProductId, segmentId }, + query + )) + .then(result => ({ items: result.domainSegments.items.map(transformDomainSegment) })); + }; -export const getDomainSegment = (contractId, dataProductId, segmentId, domainId, query) => { - return get(routes.interpolate( - routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT, - { contractId, dataProductId, segmentId, domainId }, - query - )) - .then(result => transformDomainSegment(result)); -}; + const getDomainSegment = (contractId, dataProductId, segmentId, domainId, query) => { + return xhr.get(routes.interpolate( + routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT, + { contractId, dataProductId, segmentId, domainId }, + query + )) + .then(result => transformDomainSegment(result)); + }; -export const cloneDomainSegment = (contractId, dataProductId, segmentId, domainId, newSegmentId, newDomainId) => - post( - routes.interpolate( - routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_CLONE, - { contractId, dataProductId, segmentId, domainId } - ), - { - data: JSON.stringify({ - cloneSegmentRequest: { - clonedSegmentId: newSegmentId, - domain: newDomainId - } - }) - } - ); + const cloneDomainSegment = (contractId, dataProductId, segmentId, domainId, newSegmentId, newDomainId) => + xhr.post( + routes.interpolate( + routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_CLONE, + { contractId, dataProductId, segmentId, domainId } + ), + { + data: JSON.stringify({ + cloneSegmentRequest: { + clonedSegmentId: newSegmentId, + domain: newDomainId + } + }) + } + ); -export const deleteDomainSegment = (contractId, dataProductId, segmentId, domainId) => - del( - routes.interpolate(routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT, - { contractId, dataProductId, segmentId, domainId } - )); + const deleteDomainSegment = (contractId, dataProductId, segmentId, domainId) => + xhr.del( + routes.interpolate(routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT, + { contractId, dataProductId, segmentId, domainId } + )); -export const renameDomainSegment = (contractId, dataProductId, segmentId, domainId, newSegmentId) => - post( - routes.interpolate( - routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_RENAME, - { contractId, dataProductId, segmentId, domainId } - ), - { - data: JSON.stringify({ - domainSegmentRename: { - id: newSegmentId - } - }) - } - ); + const renameDomainSegment = (contractId, dataProductId, segmentId, domainId, newSegmentId) => + xhr.post( + routes.interpolate( + routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_RENAME, + { contractId, dataProductId, segmentId, domainId } + ), + { + data: JSON.stringify({ + domainSegmentRename: { + id: newSegmentId + } + }) + } + ); -export const syncDomainSegment = (contractId, dataProductId, segmentId, domainId) => - post(routes.interpolate( - routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_SYNC, - { contractId, dataProductId, segmentId, domainId } - )); + const syncDomainSegment = (contractId, dataProductId, segmentId, domainId) => + xhr.post(routes.interpolate( + routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_SYNC, + { contractId, dataProductId, segmentId, domainId } + )); -export const deployDomainSegment = (contractId, dataProductId, segmentId, domainId, targetDomainId, synchronize) => - post( - routes.interpolate( - routes.DEPLOY_SEGMENT, - { contractId, dataProductId, segmentId, domainId }, - synchronize && { synchronize } - ), - { data: JSON.stringify({ deploySegmentRequest: { domain: targetDomainId } }) } - ); + const deployDomainSegment = (contractId, dataProductId, segmentId, domainId, targetDomainId, synchronize) => + xhr.post( + routes.interpolate( + routes.DEPLOY_SEGMENT, + { contractId, dataProductId, segmentId, domainId }, + synchronize && { synchronize } + ), + { data: JSON.stringify({ deploySegmentRequest: { domain: targetDomainId } }) } + ); -export const updateDomainSegment = domainSegment => - put(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT, domainSegment), { - data: JSON.stringify({ - domainSegment: _.omit( + const updateDomainSegment = domainSegment => + xhr.put(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT, domainSegment), { + data: JSON.stringify({ + domainSegment: omit( domainSegment, ['contractId', 'dataProductId', 'segmentId', 'domainId'] ) + }) }) - }) - .then(result => result.json()) - .then(result => transformDomainSegment(result)); + .then(result => result.json()) + .then(result => transformDomainSegment(result)); + + return { + getDomainSegments, + getDomainSegment, + cloneDomainSegment, + deleteDomainSegment, + renameDomainSegment, + syncDomainSegment, + deployDomainSegment, + updateDomainSegment + }; +} diff --git a/src/admin/domains.js b/src/admin/domains.js index f20ec9c0..fba3f0c1 100644 --- a/src/admin/domains.js +++ b/src/admin/domains.js @@ -1,4 +1,3 @@ -import { get } from '../xhr'; import * as routes from './routes'; const transformDomain = (item) => { @@ -10,17 +9,6 @@ const transformDomain = (item) => { }; }; -export const getDomain = (contractId, domainId, query) => { - const uri = routes.interpolate(routes.CONTRACT_DOMAIN, { contractId, domainId }, query); - - return get(uri).then(transformDomain); -}; - -export const getDomains = (contractId, query) => { - return get(routes.interpolate(routes.CONTRACT_DOMAINS, { contractId }, query)) - .then(result => ({ items: result.domains.items.map(transformDomain) })); // TODO: paging? -}; - const transformDomainUser = ({ user }) => { const params = routes.parse(user.links.domain, routes.CONTRACT_DOMAIN); return { @@ -31,34 +19,54 @@ const transformDomainUser = ({ user }) => { }; }; -export const getDomainUsers = (contractId, domainId, query, paging) => { - if (paging && !paging.next) { - return Promise.resolve({ items: [], paging: {} }); - } +export function createModule(xhr) { + const getDomain = (contractId, domainId, query) => { + const uri = routes.interpolate(routes.CONTRACT_DOMAIN, { contractId, domainId }, query); - const uri = paging ? - paging.next : routes.interpolate(routes.CONTRACT_DOMAIN_USERS, { contractId, domainId }, query); + return xhr.get(uri).then(transformDomain); + }; - return get(uri).then(result => ({ - ...result.domainUsers, - items: result.domainUsers.items.map(transformDomainUser) - })); -}; + const getDomains = (contractId, query) => { + return xhr.get(routes.interpolate(routes.CONTRACT_DOMAINS, { contractId }, query)) + .then(result => ({ items: result.domains.items.map(transformDomain) })); // TODO: paging? + }; -export const getDomainProjects = (contractId, domainId, state, query, paging) => { - if (paging && !paging.next) { - return Promise.resolve({ items: [], paging: {} }); - } + const getDomainUsers = (contractId, domainId, query, paging) => { + if (paging && !paging.next) { + return Promise.resolve({ items: [], paging: {} }); + } - const uri = paging ? - paging.next : routes.interpolate( - routes.CONTRACT_DOMAIN_PROJECTS, - { contractId, domainId }, state || query ? - Object.assign(state && { state }, query && { prefixSearch: query }) : null - ); + const uri = paging ? + paging.next : routes.interpolate(routes.CONTRACT_DOMAIN_USERS, { contractId, domainId }, query); - return get(uri).then(result => ({ - ...result.domainProjects, - items: result.domainProjects.items.map(item => item.project) - })); -}; + return xhr.get(uri).then(result => ({ + ...result.domainUsers, + items: result.domainUsers.items.map(transformDomainUser) + })); + }; + + const getDomainProjects = (contractId, domainId, state, query, paging) => { + if (paging && !paging.next) { + return Promise.resolve({ items: [], paging: {} }); + } + + const uri = paging ? + paging.next : routes.interpolate( + routes.CONTRACT_DOMAIN_PROJECTS, + { contractId, domainId }, state || query ? + Object.assign(state && { state }, query && { prefixSearch: query }) : null + ); + + return xhr.get(uri).then(result => ({ + ...result.domainProjects, + items: result.domainProjects.items.map(item => item.project) + })); + }; + + return { + getDomain, + getDomains, + getDomainUsers, + getDomainProjects + }; +} diff --git a/src/admin/logs.js b/src/admin/logs.js index c592e230..0b2cffae 100644 --- a/src/admin/logs.js +++ b/src/admin/logs.js @@ -1,10 +1,15 @@ -import { get } from '../xhr'; import * as routes from './routes'; -export const getLogs = (contractId, dataProductId, domainId, segmentId) => - get(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_LOG, { - contractId, - dataProductId, - domainId, - segmentId - })).then(data => data.logs.map(item => item.log)); +export function createModule(xhr) { + const getLogs = (contractId, dataProductId, domainId, segmentId) => + xhr.get(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_DOMAIN_SEGMENT_LOG, { + contractId, + dataProductId, + domainId, + segmentId + })).then(data => data.logs.map(item => item.log)); + + return { + getLogs + }; +} diff --git a/src/admin/routes.js b/src/admin/routes.js index 2e3dee55..1d940bef 100644 --- a/src/admin/routes.js +++ b/src/admin/routes.js @@ -50,8 +50,8 @@ export const DEPLOY_SEGMENT = `${CONTRACT_DOMAIN}/dataProducts/:dataProductId/se // returns params as plain object export const parse = (route, template) => { const parsedRoute = route.startsWith('http') ? - route.match(/^(https?:)\/\/(([^:/?#]*)(?::([0-9]+))?)([/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/)[5] - : route; + route.match(/^(https?:)\/\/(([^:/?#]*)(?::([0-9]+))?)([/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/)[5] + : route; const values = parsedRoute.split('/'); const views = template.split('/'); diff --git a/src/admin/segments.js b/src/admin/segments.js index 598edc51..56d5e161 100644 --- a/src/admin/segments.js +++ b/src/admin/segments.js @@ -1,45 +1,60 @@ -import { get, post, del } from '../xhr'; import * as routes from './routes'; import * as domainSegments from './domainSegments'; -export const transformSegment = (item) => { - const { contractId, dataProductId } = routes.parse(item.segment.links.self, routes.CONTRACT_DATA_PRODUCT_SEGMENT); +export function createModule(xhr) { + const transformSegment = (item) => { + const { contractId, dataProductId } = routes.parse( + item.segment.links.self, routes.CONTRACT_DATA_PRODUCT_SEGMENT + ); - const segment = { - contractId, - dataProductId, - ...item.segment + const segment = { + contractId, + dataProductId, + ...item.segment + }; + + if (segment.domainSegments) { + segment.domainSegments = segment.domainSegments.map(domainSegments.transformDomainSegment); + } + + return segment; + }; + + const getDataProductSegments = (contractId, dataProductId) => + xhr.get(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_SEGMENTS, { contractId, dataProductId })) + .then(data => ({ + items: data.segments.items.map(transformSegment), + status: data.segments.status + })); + + const createSegment = (contractId, dataProductId, segmentId, domainIds) => + xhr.post(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_SEGMENTS, { contractId, dataProductId }), { + data: JSON.stringify({ + segmentCreate: { + id: segmentId, + title: segmentId, + domains: domainIds.map( + domainId => routes.interpolate(routes.CONTRACT_DOMAIN, { contractId, domainId }) + ) + } + }) + }); + + const renameSegment = (contractId, dataProductId, segmentId, newSegmentId) => + xhr.post( + routes.interpolate(routes.CONTRACT_DATA_PRODUCT_SEGMENT_RENAME, { contractId, dataProductId, segmentId }), + { data: JSON.stringify({ segmentRename: { id: newSegmentId } }) } + ); + + const deleteSegment = (contractId, dataProductId, segmentId) => + xhr.del(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_SEGMENT, { contractId, dataProductId, segmentId })); + + return { + transformSegment, + getDataProductSegments, + createSegment, + renameSegment, + deleteSegment }; +} - if (segment.domainSegments) { - segment.domainSegments = segment.domainSegments.map(domainSegments.transformDomainSegment); - } - - return segment; -}; - -export const getDataProductSegments = (contractId, dataProductId) => - get(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_SEGMENTS, { contractId, dataProductId })).then(data => ({ - items: data.segments.items.map(transformSegment), - status: data.segments.status - })); - -export const createSegment = (contractId, dataProductId, segmentId, domainIds) => - post(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_SEGMENTS, { contractId, dataProductId }), { - data: JSON.stringify({ - segmentCreate: { - id: segmentId, - title: segmentId, - domains: domainIds.map(domainId => routes.interpolate(routes.CONTRACT_DOMAIN, { contractId, domainId })) - } - }) - }); - -export const renameSegment = (contractId, dataProductId, segmentId, newSegmentId) => - post( - routes.interpolate(routes.CONTRACT_DATA_PRODUCT_SEGMENT_RENAME, { contractId, dataProductId, segmentId }), - { data: JSON.stringify({ segmentRename: { id: newSegmentId } }) } - ); - -export const deleteSegment = (contractId, dataProductId, segmentId) => - del(routes.interpolate(routes.CONTRACT_DATA_PRODUCT_SEGMENT, { contractId, dataProductId, segmentId })); diff --git a/src/catalogue.js b/src/catalogue.js index 70caa788..74d969dd 100644 --- a/src/catalogue.js +++ b/src/catalogue.js @@ -1,6 +1,4 @@ import { get, find, omit, cloneDeep } from 'lodash'; -import { post, parseJSON } from './xhr'; -import { mdToExecutionDefinitionsAndColumns } from './execution/experimental-executions'; import { loadAttributesMap } from './utils/attributesMapLoader'; import { getAttributesDisplayForms } from './utils/visualizationObjectHelper'; @@ -19,24 +17,6 @@ const LOAD_DATE_DATASET_DEFAULTS = { includeAvailableDateAttributes: true }; -function bucketItemsToExecConfig(projectId, mdObj, options = {}) { - return mdToExecutionDefinitionsAndColumns(projectId, mdObj, options).then((definitionsAndColumns) => { - const definitions = get(definitionsAndColumns, 'definitions'); - - return get(definitionsAndColumns, 'columns', []).map((column) => { - const definition = find(definitions, ({ metricDefinition }) => - get(metricDefinition, 'identifier') === column - ); - const maql = get(definition, 'metricDefinition.expression'); - - if (maql) { - return maql; - } - return column; - }); - }); -} - /** * Convert specific params in options to "requiredDataSets" structure. For more details look into * res file https://github.com/gooddata/gdc-bear/blob/develop/resources/specification/internal/catalog.res @@ -69,70 +49,96 @@ const getRequiredDataSets = (options) => { return { requiredDataSets: { type: 'PRODUCTION' } }; }; -function loadCatalog(projectId, catalogRequest) { - const uri = `/gdc/internal/projects/${projectId}/loadCatalog`; +export function createModule(xhr, execution) { + function bucketItemsToExecConfig(projectId, mdObj, options = {}) { + return execution.mdToExecutionDefinitionsAndColumns(projectId, mdObj, options).then((definitionsAndColumns) => { + const definitions = get(definitionsAndColumns, 'definitions'); + + return get(definitionsAndColumns, 'columns', []).map((column) => { + const definition = find(definitions, ({ metricDefinition }) => + get(metricDefinition, 'identifier') === column + ); + const maql = get(definition, 'metricDefinition.expression'); + + if (maql) { + return maql; + } + return column; + }); + }); + } - return post(uri, { data: { catalogRequest } }) - .then(parseJSON) - .then(data => data.catalogResponse); -} + function loadCatalog(projectId, catalogRequest) { + const uri = `/gdc/internal/projects/${projectId}/loadCatalog`; -export function loadItems(projectId, options = {}) { - const request = omit({ - ...REQUEST_DEFAULTS, - ...options, - ...getRequiredDataSets(options) - }, [ - 'dataSetIdentifier', - 'returnAllDateDataSets', - 'attributesMap' - ]); - - const mdObj = get(cloneDeep(options), 'bucketItems'); - const attributesMap = get(options, 'attributesMap'); - const hasBuckets = get(mdObj, 'buckets') !== undefined; - if (hasBuckets) { - return bucketItemsToExecConfig(projectId, mdObj, { attributesMap }).then(bucketItems => - loadCatalog(projectId, { - ...request, - bucketItems - }) - ); + return xhr.post(uri, { data: { catalogRequest } }) + .then(xhr.parseJSON) + .then(data => data.catalogResponse); } - return loadCatalog(projectId, request); -} + function loadItems(projectId, options = {}) { + const request = omit({ + ...REQUEST_DEFAULTS, + ...options, + ...getRequiredDataSets(options) + }, [ + 'dataSetIdentifier', + 'returnAllDateDataSets', + 'attributesMap' + ]); + + const mdObj = get(cloneDeep(options), 'bucketItems'); + const attributesMap = get(options, 'attributesMap'); + const hasBuckets = get(mdObj, 'buckets') !== undefined; + if (hasBuckets) { + return bucketItemsToExecConfig(projectId, mdObj, { attributesMap }).then(bucketItems => + loadCatalog(projectId, { + ...request, + bucketItems + }) + ); + } -function requestDateDataSets(projectId, dateDataSetsRequest) { - const uri = `/gdc/internal/projects/${projectId}/loadDateDataSets`; + return loadCatalog(projectId, request); + } - return post(uri, { data: { dateDataSetsRequest } }) - .then(parseJSON) - .then(data => data.dateDataSetsResponse); -} + function requestDateDataSets(projectId, dateDataSetsRequest) { + const uri = `/gdc/internal/projects/${projectId}/loadDateDataSets`; -export function loadDateDataSets(projectId, options) { - const mdObj = get(cloneDeep(options), 'bucketItems'); - const bucketItemsPromise = mdObj ? - bucketItemsToExecConfig(projectId, mdObj, { removeDateItems: true, attributesMap: get(options, 'attributesMap') }) : - Promise.resolve(); - - return bucketItemsPromise.then((bucketItems) => { - const omittedOptions = ['filter', 'types', 'paging', 'dataSetIdentifier', 'returnAllDateDataSets', 'returnAllRelatedDateDataSets', 'attributesMap']; - // includeObjectsWithTags has higher priority than excludeObjectsWithTags, - // so when present omit excludeObjectsWithTags - if (options.includeObjectsWithTags) { - omittedOptions.push('excludeObjectsWithTags'); - } + return xhr.post(uri, { data: { dateDataSetsRequest } }) + .then(xhr.parseJSON) + .then(data => data.dateDataSetsResponse); + } - const request = omit({ - ...LOAD_DATE_DATASET_DEFAULTS, - ...REQUEST_DEFAULTS, - ...options, - ...getRequiredDataSets(options), - bucketItems - }, omittedOptions); + function loadDateDataSets(projectId, options) { + const mdObj = get(cloneDeep(options), 'bucketItems'); + const bucketItemsPromise = mdObj ? + bucketItemsToExecConfig(projectId, mdObj, { removeDateItems: true, attributesMap: get(options, 'attributesMap') }) : + Promise.resolve(); + + return bucketItemsPromise.then((bucketItems) => { + const omittedOptions = ['filter', 'types', 'paging', 'dataSetIdentifier', 'returnAllDateDataSets', 'returnAllRelatedDateDataSets', 'attributesMap']; + // includeObjectsWithTags has higher priority than excludeObjectsWithTags, + // so when present omit excludeObjectsWithTags + if (options.includeObjectsWithTags) { + omittedOptions.push('excludeObjectsWithTags'); + } + + const request = omit({ + ...LOAD_DATE_DATASET_DEFAULTS, + ...REQUEST_DEFAULTS, + ...options, + ...getRequiredDataSets(options), + bucketItems + }, omittedOptions); - return requestDateDataSets(projectId, request); - }); + return requestDateDataSets(projectId, request); + }); + } + + return { + loadItems, + loadDateDataSets + }; } + diff --git a/src/config.js b/src/config.js index a9288503..3a96f868 100644 --- a/src/config.js +++ b/src/config.js @@ -13,34 +13,43 @@ const URL_REGEXP = '(?:(https)://+|(www\\.)?)\\w[:;,\\.?\\[\\]\\w/~%&=+#-@!]*'; -// TODO - fix this -export let domain; // eslint-disable-line import/no-mutable-exports +export function createModule() { + let domain; + /** + * Sets custom domain. Parameter is url which has always to be https:// + * (if you don't provide it, we will do it for you). + * + * RegExp inspired taken from + * https://github.com/jarib/google-closure-library/blob/master/closure/goog/string/linkify.js + * @param {String|null} d valid domain starting with https:// or null for removing + * @method setCustomDomain + */ + function setCustomDomain(d) { + const sanitizedDomain = d || ''; + const link = sanitizedDomain.match(URL_REGEXP); -/** - * Sets custom domain. Parameter is url which has always to be https:// - * (if you don't provide it, we will do it for you). - * - * RegExp inspired taken from - * https://github.com/jarib/google-closure-library/blob/master/closure/goog/string/linkify.js - * @param {String|null} d valid domain starting with https:// or null for removing - * @method setCustomDomain - */ -export function setCustomDomain(d) { - const sanitizedDomain = d || ''; - const link = sanitizedDomain.match(URL_REGEXP); + if (d === null) { + domain = undefined; + return; + } + + if (!link) { + throw new Error(`${d} is not a valid url`); + } - if (d === null) { - domain = undefined; - return; + // ensure https:// prefix + // and strip possible trailing / + domain = `https://${link[0] + .replace(/^https:\/\//, '') + .replace(/\/$/, '')}`; } - if (!link) { - throw new Error(`${d} is not a valid url`); + function getDomain() { + return domain; } - // ensure https:// prefix - // and strip possible trailing / - domain = `https://${link[0] - .replace(/^https:\/\//, '') - .replace(/\/$/, '')}`; + return { + setCustomDomain, + getDomain + }; } diff --git a/src/execution.js b/src/execution.js index 25df2e8c..4d85fa0e 100644 --- a/src/execution.js +++ b/src/execution.js @@ -1,6 +1,7 @@ // Copyright (C) 2007-2017, GoodData(R) Corporation. All rights reserved. -import { getData } from './execution/experimental-executions'; -import executeAfm from './execution/execute-afm'; +import { createModule as experimentalExecutionsFactory } from './execution/experimental-executions'; +import { createModule as loadAttributesMapFactory } from './utils/attributesMapLoader'; +import { createModule as executeAfmFactory } from './execution/execute-afm'; /** * Execution endpoints @@ -9,7 +10,15 @@ import executeAfm from './execution/execute-afm'; * @class execution * */ -export default { - getData, - executeAfm -}; +export function createModule(xhr, md) { + const loadAttributesMap = loadAttributesMapFactory(md); + const { + getData, + mdToExecutionDefinitionsAndColumns + } = experimentalExecutionsFactory(xhr, loadAttributesMap); + return { + getData, + mdToExecutionDefinitionsAndColumns, + executeAfm: executeAfmFactory(xhr) + }; +} diff --git a/src/execution/execute-afm.js b/src/execution/execute-afm.js index 81c305c9..60901293 100644 --- a/src/execution/execute-afm.js +++ b/src/execution/execute-afm.js @@ -2,7 +2,6 @@ import { get, clone } from 'lodash'; import invariant from 'invariant'; import qs from 'qs'; -import { ajax, post, parseJSON } from '../xhr'; const PAGE_SIZE = 500; const DEFAULT_DIMENSION_COUNT = 2; @@ -18,22 +17,6 @@ function getLimit(offset) { return Array(offset.length).fill(PAGE_SIZE); } -function fetchExecutionResult(pollingUri, offset) { - const [uriPart, queryPart] = pollingUri.split(/\?(.+)/); - const query = { - ...qs.parse(queryPart), - limit: getLimit(offset).join(','), - offset: offset.join(',') - }; - const finalPollingUri = uriPart + qs.stringify(query, { addQueryPrefix: true }); - return ajax(finalPollingUri, { method: 'GET' }).then((r) => { - if (r.status === 204) { - return null; - } - return r.json(); - }); -} - // works only for one or two dimensions export function mergePageData(result, currentPage) { const { paging, data, headerItems } = currentPage.executionResult; @@ -79,45 +62,65 @@ export function nextPageOffset({ offset, total }) { return false; } -function getOnePage(pollingUri, offset, prevResult = null) { - return fetchExecutionResult(pollingUri, offset).then((executionResult) => { - if (executionResult === null) { - return null; - } +export function createModule(xhr) { + function fetchExecutionResult(pollingUri, offset) { + const [uriPart, queryPart] = pollingUri.split(/\?(.+)/); + const query = { + ...qs.parse(queryPart), + limit: getLimit(offset).join(','), + offset: offset.join(',') + }; + const finalPollingUri = uriPart + qs.stringify(query, { addQueryPrefix: true }); + return xhr.ajax(finalPollingUri, { method: 'GET' }).then((r) => { + if (r.status === 204) { + return null; + } + return r.json(); + }); + } - const newResult = prevResult ? mergePageData(prevResult, executionResult) : executionResult; + function getOnePage(pollingUri, offset, prevResult = null) { + return fetchExecutionResult(pollingUri, offset).then((executionResult) => { + if (executionResult === null) { + return null; + } - const nextOffset = nextPageOffset(executionResult.executionResult.paging); - return nextOffset - ? getOnePage(pollingUri, nextOffset, newResult) - : newResult; - }); -} + const newResult = prevResult ? mergePageData(prevResult, executionResult) : executionResult; + + const nextOffset = nextPageOffset(executionResult.executionResult.paging); + return nextOffset + ? getOnePage(pollingUri, nextOffset, newResult) + : newResult; + }); + } -/** - * Execute AFM and fetch data results - * - * @method executeAfm - * @param {String} projectId - GD project identifier - * @param {Object} execution - See https://github.com/gooddata/gooddata-typings/blob/master/index.ts#L4 - * - * @return {Object} Structure with `executionResult` and `executionResponse` - - * See https://github.com/gooddata/gooddata-typings/blob/master/index.ts#L294 - */ -export default function executeAfm(projectId, execution) { - const dimensionality = getDimensionality(execution); - invariant(dimensionality <= 2, 'executeAfm does not support more than 2 dimensions'); + /** + * Execute AFM and fetch data results + * + * @method executeAfm + * @param {String} projectId - GD project identifier + * @param {Object} execution - See https://github.com/gooddata/gooddata-typings/blob/master/index.ts#L4 + * + * @return {Object} Structure with `executionResult` and `executionResponse` - + * See https://github.com/gooddata/gooddata-typings/blob/master/index.ts#L294 + */ + function executeAfm(projectId, execution) { + const dimensionality = getDimensionality(execution); + invariant(dimensionality <= 2, 'executeAfm does not support more than 2 dimensions'); - return post(`/gdc/app/projects/${projectId}/executeAfm`, { body: JSON.stringify(execution) }) - .then(parseJSON) - .then((executionResponse) => { - const offset = Array(dimensionality).fill(0); // offset holds information on dimensionality - const pollingUri = executionResponse.executionResponse.links.executionResult; - return getOnePage(pollingUri, offset).then((executionResult) => { - return { - executionResponse, - executionResult - }; + return xhr.post(`/gdc/app/projects/${projectId}/executeAfm`, { body: JSON.stringify(execution) }) + .then(xhr.parseJSON) + .then((executionResponse) => { + const offset = Array(dimensionality).fill(0); // offset holds information on dimensionality + const pollingUri = executionResponse.executionResponse.links.executionResult; + return getOnePage(pollingUri, offset).then((executionResult) => { + return { + executionResponse, + executionResult + }; + }); }); - }); + } + + return executeAfm; } diff --git a/src/execution/experimental-executions.js b/src/execution/experimental-executions.js index a348d50d..74169687 100644 --- a/src/execution/experimental-executions.js +++ b/src/execution/experimental-executions.js @@ -18,16 +18,9 @@ import { set } from 'lodash'; -import { - ajax, - post, - parseJSON -} from '../xhr'; - import Rules from '../utils/rules'; import { sortDefinitions } from '../utils/definitions'; import { - loadAttributesMap, getMissingUrisInAttributesMap } from '../utils/attributesMapLoader'; import { @@ -66,117 +59,6 @@ const emptyResult = { } }; -function loadExtendedDataResults(uri, settings, prevResult = emptyResult) { - return new Promise((resolve, reject) => { - ajax(uri, settings) - .then((r) => { - if (r.status === 204) { - return { - status: r.status, - result: '' - }; - } - - return r.json().then((result) => { - return { - status: r.status, - result - }; - }); - }) - .then(({ status, result }) => { - const values = [ - ...get(prevResult, 'extendedTabularDataResult.values', []), - ...get(result, 'extendedTabularDataResult.values', []) - ]; - - const warnings = [ - ...get(prevResult, 'extendedTabularDataResult.warnings', []), - ...get(result, 'extendedTabularDataResult.warnings', []) - ]; - - const updatedResult = merge({}, prevResult, { - extendedTabularDataResult: { - values, - warnings - } - }); - - const nextUri = get(result, 'extendedTabularDataResult.paging.next'); - if (nextUri) { - resolve(loadExtendedDataResults(nextUri, settings, updatedResult)); - } else { - resolve({ status, result: updatedResult }); - } - }, reject); - }); -} - -/** - * Module for execution on experimental execution resource - * - * @class execution - * @module execution - */ - -/** - * For the given projectId it returns table structure with the given - * elements in column headers. - * - * @method getData - * @param {String} projectId - GD project identifier - * @param {Array} columns - An array of attribute or metric identifiers. - * @param {Object} executionConfiguration - Execution configuration - can contain for example - * property "where" containing query-like filters - * property "orderBy" contains array of sorted properties to order in form - * [{column: 'identifier', direction: 'asc|desc'}] - * @param {Object} settings - Supports additional settings accepted by the underlying - * xhr.ajax() calls - * - * @return {Object} Structure with `headers` and `rawData` keys filled with values from execution. - */ -export function getData(projectId, columns, executionConfiguration = {}, settings = {}) { - const executedReport = { - isLoaded: false - }; - - // Create request and result structures - const request = { - execution: { columns } - }; - // enrich configuration with supported properties such as - // where clause with query-like filters - ['where', 'orderBy', 'definitions'].forEach((property) => { - if (executionConfiguration[property]) { - request.execution[property] = executionConfiguration[property]; - } - }); - - // Execute request - return post(`/gdc/internal/projects/${projectId}/experimental/executions`, { - ...settings, - body: JSON.stringify(request) - }) - .then(parseJSON) - .then((result) => { - executedReport.headers = wrapMeasureIndexesFromMappings( - get(executionConfiguration, 'metricMappings'), get(result, ['executionResult', 'headers'], [])); - - // Start polling on url returned in the executionResult for tabularData - return loadExtendedDataResults(result.executionResult.extendedTabularDataResult, settings); - }) - .then((r) => { - const { result, status } = r; - - return Object.assign({}, executedReport, { - rawData: get(result, 'extendedTabularDataResult.values', []), - warnings: get(result, 'extendedTabularDataResult.warnings', []), - isLoaded: true, - isEmpty: status === 204 - }); - }); -} - const MAX_TITLE_LENGTH = 1000; function getMetricTitle(suffix, title) { @@ -558,18 +440,6 @@ function getMetricFactory(measure, mdObj) { return factory; } -function getAttributesMap(options, displayFormUris, projectId) { - const attributesMap = get(options, 'attributesMap', {}); - - const missingUris = getMissingUrisInAttributesMap(displayFormUris, attributesMap); - return loadAttributesMap(projectId, missingUris).then((result) => { - return { - ...attributesMap, - ...result - }; - }); -} - function getExecutionDefinitionsAndColumns(mdObj, options, attributesMap) { const measures = getMeasures(mdObj); let attributes = getAttributes(mdObj); @@ -589,11 +459,141 @@ function getExecutionDefinitionsAndColumns(mdObj, options, attributesMap) { }; } -export const mdToExecutionDefinitionsAndColumns = (projectId, mdObj, options = {}) => { - const allDfUris = getAttributesDisplayForms(mdObj); - const attributesMapPromise = getAttributesMap(options, allDfUris, projectId); +export function createModule(xhr, loadAttributesMap) { + function getAttributesMap(options, displayFormUris, projectId) { + const attributesMap = get(options, 'attributesMap', {}); - return attributesMapPromise.then((attributesMap) => { - return getExecutionDefinitionsAndColumns(mdObj, options, attributesMap); - }); -}; + const missingUris = getMissingUrisInAttributesMap(displayFormUris, attributesMap); + return loadAttributesMap(projectId, missingUris).then((result) => { + return { + ...attributesMap, + ...result + }; + }); + } + + function mdToExecutionDefinitionsAndColumns(projectId, mdObj, options = {}) { + const allDfUris = getAttributesDisplayForms(mdObj); + const attributesMapPromise = getAttributesMap(options, allDfUris, projectId); + + return attributesMapPromise.then((attributesMap) => { + return getExecutionDefinitionsAndColumns(mdObj, options, attributesMap); + }); + } + + function loadExtendedDataResults(uri, settings, prevResult = emptyResult) { + return new Promise((resolve, reject) => { + xhr.ajax(uri, settings) + .then((r) => { + if (r.status === 204) { + return { + status: r.status, + result: '' + }; + } + + return r.json().then((result) => { + return { + status: r.status, + result + }; + }); + }) + .then(({ status, result }) => { + const values = [ + ...get(prevResult, 'extendedTabularDataResult.values', []), + ...get(result, 'extendedTabularDataResult.values', []) + ]; + + const warnings = [ + ...get(prevResult, 'extendedTabularDataResult.warnings', []), + ...get(result, 'extendedTabularDataResult.warnings', []) + ]; + + const updatedResult = merge({}, prevResult, { + extendedTabularDataResult: { + values, + warnings + } + }); + + const nextUri = get(result, 'extendedTabularDataResult.paging.next'); + if (nextUri) { + resolve(loadExtendedDataResults(nextUri, settings, updatedResult)); + } else { + resolve({ status, result: updatedResult }); + } + }, reject); + }); + } + + /** + * Module for execution on experimental execution resource + * + * @class execution + * @module execution + */ + + /** + * For the given projectId it returns table structure with the given + * elements in column headers. + * + * @method getData + * @param {String} projectId - GD project identifier + * @param {Array} columns - An array of attribute or metric identifiers. + * @param {Object} executionConfiguration - Execution configuration - can contain for example + * property "where" containing query-like filters + * property "orderBy" contains array of sorted properties to order in form + * [{column: 'identifier', direction: 'asc|desc'}] + * @param {Object} settings - Supports additional settings accepted by the underlying + * xhr.ajax() calls + * + * @return {Object} Structure with `headers` and `rawData` keys filled with values from execution. + */ + function getData(projectId, columns, executionConfiguration = {}, settings = {}) { + const executedReport = { + isLoaded: false + }; + + // Create request and result structures + const request = { + execution: { columns } + }; + // enrich configuration with supported properties such as + // where clause with query-like filters + ['where', 'orderBy', 'definitions'].forEach((property) => { + if (executionConfiguration[property]) { + request.execution[property] = executionConfiguration[property]; + } + }); + + // Execute request + return xhr.post(`/gdc/internal/projects/${projectId}/experimental/executions`, { + ...settings, + body: JSON.stringify(request) + }) + .then(xhr.parseJSON) + .then((result) => { + executedReport.headers = wrapMeasureIndexesFromMappings( + get(executionConfiguration, 'metricMappings'), get(result, ['executionResult', 'headers'], [])); + + // Start polling on url returned in the executionResult for tabularData + return loadExtendedDataResults(result.executionResult.extendedTabularDataResult, settings); + }) + .then((r) => { + const { result, status } = r; + + return Object.assign({}, executedReport, { + rawData: get(result, 'extendedTabularDataResult.values', []), + warnings: get(result, 'extendedTabularDataResult.warnings', []), + isLoaded: true, + isEmpty: status === 204 + }); + }); + } + + return { + getData, + mdToExecutionDefinitionsAndColumns + }; +} diff --git a/src/gooddata-browser.js b/src/gooddata-browser.js index 7a8ee048..f6fc4141 100644 --- a/src/gooddata-browser.js +++ b/src/gooddata-browser.js @@ -1,7 +1,7 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetch from 'isomorphic-fetch'; import { setFetch } from './utils/fetch'; -import gooddata from './gooddata'; +import defaultInstance, { factory } from './gooddata'; // Fetch requests will be sent through the isomorphic-fetch. Our authentication // relies on cookies, so it will work in browser environment automatically. @@ -9,6 +9,5 @@ import gooddata from './gooddata'; // For node see `gooddata-node.js` file. setFetch(fetch); -export default gooddata; -module.exports = gooddata; - +export { factory }; +export default defaultInstance; diff --git a/src/gooddata-node.js b/src/gooddata-node.js index 64e5e9a8..86e6609c 100644 --- a/src/gooddata-node.js +++ b/src/gooddata-node.js @@ -1,4 +1,4 @@ -import gooddata from './gooddata'; +import defaultInstance, { factory } from './gooddata'; import { setFetch } from './utils/fetch'; // Fetch requests will be sent through the node-fetch wrapped by the fetch-cookie. @@ -7,5 +7,7 @@ import { setFetch } from './utils/fetch'; // immediately. setFetch(require('fetch-cookie')(require('node-fetch'))); -export default gooddata; -module.exports = gooddata; +// Backward compatibility +defaultInstance.factory = factory; // eslint-disable-line import/no-named-as-default-member +export default defaultInstance; +module.exports = defaultInstance; diff --git a/src/gooddata.js b/src/gooddata.js index a87527b9..3686bfd8 100644 --- a/src/gooddata.js +++ b/src/gooddata.js @@ -1,12 +1,12 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. -import * as xhr from './xhr'; -import * as user from './user'; -import * as md from './metadata'; -import execution from './execution'; -import * as project from './project'; -import * as config from './config'; -import * as catalogue from './catalogue'; -import admin from './admin'; +import { createModule as xhrFactory } from './xhr'; +import { createModule as userFactory } from './user'; +import { createModule as metadataFactory } from './metadata'; +import { createModule as executionFactory } from './execution'; +import { createModule as projectFactory } from './project'; +import { createModule as configFactory } from './config'; +import { createModule as catalogueFactory } from './catalogue'; +import { createModule as adminFactory } from './admin'; /** * # JS SDK @@ -25,7 +25,34 @@ import admin from './admin'; * @module sdk * @class sdk */ -const gooddata = { config, xhr, user, md, execution, project, catalogue, admin }; -export default gooddata; -module.exports = gooddata; +function factory(options = {}) { + const config = configFactory(); + if (options.domain) { + config.setCustomDomain(options.domain); + } + const xhr = xhrFactory(config); + const md = metadataFactory(xhr); + const execution = executionFactory(xhr, md); + return { + config, + xhr, + user: userFactory(xhr), + md, + execution, + project: projectFactory(xhr), + catalogue: catalogueFactory(xhr, execution), + admin: adminFactory(xhr) + }; +} + +let defaultInstance; // eslint-disable-line import/no-mutable-exports +if (!defaultInstance) { + defaultInstance = factory(); +} + +export { + factory +}; + +export default defaultInstance; diff --git a/src/metadata.js b/src/metadata.js index dfa648c9..9418da38 100644 --- a/src/metadata.js +++ b/src/metadata.js @@ -6,7 +6,6 @@ import { flatten, pick } from 'lodash'; -import { ajax, get, post, del, parseJSON } from './xhr'; import { getIn, handlePolling, queryString } from './util'; /** @@ -15,30 +14,98 @@ import { getIn, handlePolling, queryString } from './util'; * @class metadata * @module metadata */ +export function createModule(xhr) { + /** + * Load all objects with given uris + * (use bulk loading instead of getting objects one by one) + * + * @method getObjects + * @param {String} projectId id of the project + * @param {Array} objectUris array of uris for objects to be loaded + * @return {Array} array of loaded elements + */ + function getObjects(projectId, objectUris) { + const LIMIT = 50; + const uri = `/gdc/md/${projectId}/objects/get`; + + const objectsUrisChunks = chunk(objectUris, LIMIT); + + const promises = objectsUrisChunks.map((objectUrisChunk) => { + const data = { + get: { + items: objectUrisChunk + } + }; + + return xhr.post(uri, { + data: JSON.stringify(data) + }).then((r) => { + if (!r.ok) { + const err = new Error(r.statusText); + err.response = r; + throw err; + } -/** - * Load all objects with given uris - * (use bulk loading instead of getting objects one by one) - * - * @method getObjects - * @param {String} projectId id of the project - * @param {Array} objectUris array of uris for objects to be loaded - * @return {Array} array of loaded elements - */ -export function getObjects(projectId, objectUris) { - const LIMIT = 50; - const uri = `/gdc/md/${projectId}/objects/get`; + return r.json(); + }).then(result => _get(result, ['objects', 'items'])); + }); + + return Promise.all(promises).then(flatten); + } - const objectsUrisChunks = chunk(objectUris, LIMIT); + /** + * Loads all objects by query (fetches all pages, one by one) + * + * @method getObjectsByQuery + * @param {String} projectId id of the project + * @param {Object} options (see https://developer.gooddata.com/api endpoint: /gdc/md/{project_id}/objects/query) + * - category {String} for example 'dataSets' or 'projectDashboard' + * - mode {String} 'enriched' or 'raw' + * - author {String} the URI of the author of the metadata objects + * - limit {number} default is 50 (also maximum) + * @return {Promise} array of returned objects + */ + function getObjectsByQuery(projectId, options) { + function getOnePage(uri, items = []) { + return xhr.get(uri) + .then(({ objects }) => { + items.push(...objects.items); + const nextUri = objects.paging.next; + return nextUri ? getOnePage(nextUri, items) : items; + }); + } + + const uri = `/gdc/md/${projectId}/objects/query`; + const query = pick({ limit: 50, ...options }, ['category', 'mode', 'author', 'limit']); + return getOnePage(uri + queryString(query)); + } + + /** + * Get MD objects from using2 resource. Include only objects of given types + * and take care about fetching only nearest objects if requested. + * + * @method getObjectUsing + * @param {String} projectId id of the project + * @param {String} uri uri of the object for which dependencies are to be found + * @param {Object} options objects with options: + * - types {Array} array of strings with object types to be included + * - nearest {Boolean} whether to include only nearest dependencies + * @return {jQuery promise} promise promise once resolved returns an array of + * entries returned by using2 resource + */ + function getObjectUsing(projectId, uri, options = {}) { + const { types = [], nearest = false } = options; + const resourceUri = `/gdc/md/${projectId}/using2`; - const promises = objectsUrisChunks.map((objectUrisChunk) => { const data = { - get: { - items: objectUrisChunk + inUse: { + uri, + types, + nearest: nearest ? 1 : 0 } }; - return post(uri, { + return xhr.post(resourceUri, { data: JSON.stringify(data) }).then((r) => { if (!r.ok) { @@ -48,636 +115,594 @@ export function getObjects(projectId, objectUris) { } return r.json(); - }).then(result => _get(result, ['objects', 'items'])); - }); + }).then(result => result.entries); + } - return Promise.all(promises).then(flatten); -} + /** + * Get MD objects from using2 resource. Include only objects of given types + * and take care about fetching only nearest objects if requested. + * + * @method getObjectUsingMany + * @param {String} projectId id of the project + * @param {Array} uris uris of objects for which dependencies are to be found + * @param {Object} options objects with options: + * - types {Array} array of strings with object types to be included + * - nearest {Boolean} whether to include only nearest dependencies + * @return {jQuery promise} promise promise once resolved returns an array of + * entries returned by using2 resource + */ + function getObjectUsingMany(projectId, uris, options = {}) { + const { types = [], nearest = false } = options; + const resourceUri = `/gdc/md/${projectId}/using2`; -/** - * Loads all objects by query (fetches all pages, one by one) - * - * @method getObjectsByQuery - * @param {String} projectId id of the project - * @param {Object} options (see https://developer.gooddata.com/api endpoint: /gdc/md/{project_id}/objects/query) - * - category {String} for example 'dataSets' or 'projectDashboard' - * - mode {String} 'enriched' or 'raw' - * - author {String} the URI of the author of the metadata objects - * - limit {number} default is 50 (also maximum) - * @return {Promise} array of returned objects - */ -export function getObjectsByQuery(projectId, options) { - function getOnePage(uri, items = []) { - return get(uri) - .then(({ objects }) => { - items.push(...objects.items); - const nextUri = objects.paging.next; - return nextUri ? getOnePage(nextUri, items) : items; - }); - } + const data = { + inUseMany: { + uris, + types, + nearest: nearest ? 1 : 0 + } + }; - const uri = `/gdc/md/${projectId}/objects/query`; - const query = pick({ limit: 50, ...options }, ['category', 'mode', 'author', 'limit']); - return getOnePage(uri + queryString(query)); -} + return xhr.post(resourceUri, { + data: JSON.stringify(data) + }).then((r) => { + if (!r.ok) { + const err = new Error(r.statusText); + err.response = r; + throw err; + } + return r.json(); + }).then(result => result.useMany); + } -/** - * Get MD objects from using2 resource. Include only objects of given types - * and take care about fetching only nearest objects if requested. - * - * @method getObjectUsing - * @param {String} projectId id of the project - * @param {String} uri uri of the object for which dependencies are to be found - * @param {Object} options objects with options: - * - types {Array} array of strings with object types to be included - * - nearest {Boolean} whether to include only nearest dependencies - * @return {jQuery promise} promise promise once resolved returns an array of - * entries returned by using2 resource - */ -export function getObjectUsing(projectId, uri, options = {}) { - const { types = [], nearest = false } = options; - const resourceUri = `/gdc/md/${projectId}/using2`; - - const data = { - inUse: { - uri, - types, - nearest: nearest ? 1 : 0 - } - }; + /** + * Returns all visualizations metadata in a project specified by projectId param + * + * @method getVisualizations + * @param {string} projectId Project identifier + * @return {Array} An array of visualization objects + */ + function getVisualizations(projectId) { + return xhr.get(`/gdc/md/${projectId}/query/visualizations`).then(r => (r.ok ? r.json() : r)).then(getIn('query.entries')); + } - return post(resourceUri, { - data: JSON.stringify(data) - }).then((r) => { - if (!r.ok) { - const err = new Error(r.statusText); - err.response = r; - throw err; - } + /** + * Returns all attributes in a project specified by projectId param + * + * @method getAttributes + * @param {string} projectId Project identifier + * @return {Array} An array of attribute objects + */ + function getAttributes(projectId) { + return xhr.get(`/gdc/md/${projectId}/query/attributes`).then(r => (r.ok ? r.json() : r)).then(getIn('query.entries')); + } - return r.json(); - }).then(result => result.entries); -} + /** + * Returns all dimensions in a project specified by projectId param + * + * @method getDimensions + * @param {string} projectId Project identifier + * @return {Array} An array of dimension objects + * @see getFolders + */ + function getDimensions(projectId) { + return xhr.get(`/gdc/md/${projectId}/query/dimensions`).then(r => (r.ok ? r.json() : r)).then(getIn('query.entries')); + } -/** - * Get MD objects from using2 resource. Include only objects of given types - * and take care about fetching only nearest objects if requested. - * - * @method getObjectUsingMany - * @param {String} projectId id of the project - * @param {Array} uris uris of objects for which dependencies are to be found - * @param {Object} options objects with options: - * - types {Array} array of strings with object types to be included - * - nearest {Boolean} whether to include only nearest dependencies - * @return {jQuery promise} promise promise once resolved returns an array of - * entries returned by using2 resource - */ -export function getObjectUsingMany(projectId, uris, options = {}) { - const { types = [], nearest = false } = options; - const resourceUri = `/gdc/md/${projectId}/using2`; - - const data = { - inUseMany: { - uris, - types, - nearest: nearest ? 1 : 0 + /** + * Returns project folders. Folders can be of specific types and you can specify + * the type you need by passing and optional `type` parameter + * + * @method getFolders + * @param {String} projectId - Project identifier + * @param {String} type - Optional, possible values are `metric`, `fact`, `attribute` + * @return {Array} An array of dimension objects + */ + function getFolders(projectId, type) { + function getFolderEntries(pId, t) { + const typeURL = t ? `?type=${t}` : ''; + + return xhr.get(`/gdc/md/${pId}/query/folders${typeURL}`).then(getIn('query.entries')); } - }; - return post(resourceUri, { - data: JSON.stringify(data) - }).then((r) => { - if (!r.ok) { - const err = new Error(r.statusText); - err.response = r; - throw err; + switch (type) { + case 'fact': + case 'metric': + return getFolderEntries(projectId, type); + case 'attribute': + return getDimensions(projectId); + default: + return Promise.all([ + getFolderEntries(projectId, 'fact'), + getFolderEntries(projectId, 'metric'), + getDimensions(projectId) + ]) + .then(([facts, metrics, attributes]) => { + return { fact: facts, metric: metrics, attribute: attributes }; + }); } - - return r.json(); - }).then(result => result.useMany); -} - -/** - * Returns all visualizations metadata in a project specified by projectId param - * - * @method getVisualizations - * @param {string} projectId Project identifier - * @return {Array} An array of visualization objects - */ -export function getVisualizations(projectId) { - return get(`/gdc/md/${projectId}/query/visualizations`).then(r => (r.ok ? r.json() : r)).then(getIn('query.entries')); -} - -/** -* Returns all attributes in a project specified by projectId param -* -* @method getAttributes -* @param {string} projectId Project identifier -* @return {Array} An array of attribute objects -*/ -export function getAttributes(projectId) { - return get(`/gdc/md/${projectId}/query/attributes`).then(r => (r.ok ? r.json() : r)).then(getIn('query.entries')); -} - -/** - * Returns all dimensions in a project specified by projectId param - * - * @method getDimensions - * @param {string} projectId Project identifier - * @return {Array} An array of dimension objects - * @see getFolders - */ -export function getDimensions(projectId) { - return get(`/gdc/md/${projectId}/query/dimensions`).then(r => (r.ok ? r.json() : r)).then(getIn('query.entries')); -} - -/** - * Returns project folders. Folders can be of specific types and you can specify - * the type you need by passing and optional `type` parameter - * - * @method getFolders - * @param {String} projectId - Project identifier - * @param {String} type - Optional, possible values are `metric`, `fact`, `attribute` - * @return {Array} An array of dimension objects - */ -export function getFolders(projectId, type) { - function getFolderEntries(pId, t) { - const typeURL = t ? `?type=${t}` : ''; - - return get(`/gdc/md/${pId}/query/folders${typeURL}`).then(getIn('query.entries')); } - switch (type) { - case 'fact': - case 'metric': - return getFolderEntries(projectId, type); - case 'attribute': - return getDimensions(projectId); - default: - return Promise.all([ - getFolderEntries(projectId, 'fact'), - getFolderEntries(projectId, 'metric'), - getDimensions(projectId) - ]) - .then(([facts, metrics, attributes]) => { - return { fact: facts, metric: metrics, attribute: attributes }; - }); + /** + * Returns all facts in a project specified by the given projectId + * + * @method getFacts + * @param {string} projectId Project identifier + * @return {Array} An array of fact objects + */ + function getFacts(projectId) { + return xhr.get(`/gdc/md/${projectId}/query/facts`).then(r => (r.ok ? r.json() : r)).then(getIn('query.entries')); } -} - -/** - * Returns all facts in a project specified by the given projectId - * - * @method getFacts - * @param {string} projectId Project identifier - * @return {Array} An array of fact objects - */ -export function getFacts(projectId) { - return get(`/gdc/md/${projectId}/query/facts`).then(r => (r.ok ? r.json() : r)).then(getIn('query.entries')); -} - -/** - * Returns all metrics in a project specified by the given projectId - * - * @method getMetrics - * @param {string} projectId Project identifier - * @return {Array} An array of metric objects - */ -export function getMetrics(projectId) { - return get(`/gdc/md/${projectId}/query/metrics`).then(r => (r.ok ? r.json() : r)).then(getIn('query.entries')); -} -/** - * Returns all metrics that are reachable (with respect to ldm of the project - * specified by the given projectId) for given attributes - * - * @method getAvailableMetrics - * @param {String} projectId - Project identifier - * @param {Array} attrs - An array of attribute uris for which we want to get - * availabale metrics - * @return {Array} An array of reachable metrics for the given attrs - * @see getAvailableAttributes - * @see getAvailableFacts - */ -export function getAvailableMetrics(projectId, attrs) { - return post(`/gdc/md/${projectId}/availablemetrics`, { - data: JSON.stringify(attrs) - }).then(r => (r.ok ? r.json() : r)).then(r => r.entries); -} + /** + * Returns all metrics in a project specified by the given projectId + * + * @method getMetrics + * @param {string} projectId Project identifier + * @return {Array} An array of metric objects + */ + function getMetrics(projectId) { + return xhr.get(`/gdc/md/${projectId}/query/metrics`).then(r => (r.ok ? r.json() : r)).then(getIn('query.entries')); + } -/** - * Returns all attributes that are reachable (with respect to ldm of the project - * specified by the given projectId) for given metrics (also called as drillCrossPath) - * - * @method getAvailableAttributes - * @param {String} projectId - Project identifier - * @param {Array} metrics - An array of metric uris for which we want to get - * availabale attributes - * @return {Array} An array of reachable attributes for the given metrics - * @see getAvailableMetrics - * @see getAvailableFacts - */ -export function getAvailableAttributes(projectId, metrics) { - return post(`/gdc/md/${projectId}/drillcrosspaths`, { - body: JSON.stringify(metrics) - }).then(r => (r.ok ? r.json() : r)).then(r => r.drillcrosspath.links); -} + /** + * Returns all metrics that are reachable (with respect to ldm of the project + * specified by the given projectId) for given attributes + * + * @method getAvailableMetrics + * @param {String} projectId - Project identifier + * @param {Array} attrs - An array of attribute uris for which we want to get + * availabale metrics + * @return {Array} An array of reachable metrics for the given attrs + * @see getAvailableAttributes + * @see getAvailableFacts + */ + function getAvailableMetrics(projectId, attrs) { + return xhr.post(`/gdc/md/${projectId}/availablemetrics`, { + data: JSON.stringify(attrs) + }).then(r => (r.ok ? r.json() : r)).then(r => r.entries); + } -/** - * Returns all attributes that are reachable (with respect to ldm of the project - * specified by the given projectId) for given metrics (also called as drillCrossPath) - * - * @method getAvailableFacts - * @param {String} projectId - Project identifier - * @param {Array} items - An array of metric or attribute uris for which we want to get - * availabale facts - * @return {Array} An array of reachable facts for the given items - * @see getAvailableAttributes - * @see getAvailableMetrics - */ -export function getAvailableFacts(projectId, items) { - return post(`/gdc/md/${projectId}/availablefacts`, { - data: JSON.stringify(items) - }).then(r => (r.ok ? r.json() : r)).then(r => r.entries); -} + /** + * Returns all attributes that are reachable (with respect to ldm of the project + * specified by the given projectId) for given metrics (also called as drillCrossPath) + * + * @method getAvailableAttributes + * @param {String} projectId - Project identifier + * @param {Array} metrics - An array of metric uris for which we want to get + * availabale attributes + * @return {Array} An array of reachable attributes for the given metrics + * @see getAvailableMetrics + * @see getAvailableFacts + */ + function getAvailableAttributes(projectId, metrics) { + return xhr.post(`/gdc/md/${projectId}/drillcrosspaths`, { + body: JSON.stringify(metrics) + }).then(r => (r.ok ? r.json() : r)).then(r => r.drillcrosspath.links); + } -/** - * Get details of a metadata object specified by its uri - * - * @method getObjectDetails - * @param uri uri of the metadata object for which details are to be retrieved - * @return {Object} object details - */ -export function getObjectDetails(uri) { - return get(uri); -} + /** + * Returns all attributes that are reachable (with respect to ldm of the project + * specified by the given projectId) for given metrics (also called as drillCrossPath) + * + * @method getAvailableFacts + * @param {String} projectId - Project identifier + * @param {Array} items - An array of metric or attribute uris for which we want to get + * availabale facts + * @return {Array} An array of reachable facts for the given items + * @see getAvailableAttributes + * @see getAvailableMetrics + */ + function getAvailableFacts(projectId, items) { + return xhr.post(`/gdc/md/${projectId}/availablefacts`, { + data: JSON.stringify(items) + }).then(r => (r.ok ? r.json() : r)).then(r => r.entries); + } -/** - * Get folders with items. - * Returns array of folders, each having a title and items property which is an array of - * corresponding items. Each item is either a metric or attribute, keeping its original - * verbose structure. - * - * @method getFoldersWithItems - * @param {String} type type of folders to return - * @return {Array} Array of folder object, each containing title and - * corresponding items. - */ + /** + * Get details of a metadata object specified by its uri + * + * @method getObjectDetails + * @param uri uri of the metadata object for which details are to be retrieved + * @return {Object} object details + */ + function getObjectDetails(uri) { + return xhr.get(uri); + } -export function getFoldersWithItems(projectId, type) { - // fetch all folders of given type and process them - return getFolders(projectId, type).then((folders) => { - // Helper function to get details for each metric in the given - // array of links to the metadata objects representing the metrics. - // @return the array of promises - function getMetricItemsDetails(array) { - return Promise.all(array.map(getObjectDetails)).then((metricArgs) => { - return metricArgs.map(item => item.metric); - }); - } + /** + * Get folders with items. + * Returns array of folders, each having a title and items property which is an array of + * corresponding items. Each item is either a metric or attribute, keeping its original + * verbose structure. + * + * @method getFoldersWithItems + * @param {String} type type of folders to return + * @return {Array} Array of folder object, each containing title and + * corresponding items. + */ + function getFoldersWithItems(projectId, type) { + // fetch all folders of given type and process them + return getFolders(projectId, type).then((folders) => { + // Helper function to get details for each metric in the given + // array of links to the metadata objects representing the metrics. + // @return the array of promises + function getMetricItemsDetails(array) { + return Promise.all(array.map(getObjectDetails)).then((metricArgs) => { + return metricArgs.map(item => item.metric); + }); + } - // helper mapBy function - function mapBy(array, key) { - return array.map((item) => { - return item[key]; - }); - } + // helper mapBy function + function mapBy(array, key) { + return array.map((item) => { + return item[key]; + }); + } - // helper for sorting folder tree structure - // sadly @returns void (sorting == mutating array in js) - const sortFolderTree = (structure) => { - structure.forEach((folder) => { - folder.items.sort((a, b) => { - if (a.meta.title < b.meta.title) { + // helper for sorting folder tree structure + // sadly @returns void (sorting == mutating array in js) + const sortFolderTree = (structure) => { + structure.forEach((folder) => { + folder.items.sort((a, b) => { + if (a.meta.title < b.meta.title) { + return -1; + } else if (a.meta.title > b.meta.title) { + return 1; + } + + return 0; + }); + }); + structure.sort((a, b) => { + if (a.title < b.title) { return -1; - } else if (a.meta.title > b.meta.title) { + } else if (a.title > b.title) { return 1; } return 0; }); - }); - structure.sort((a, b) => { - if (a.title < b.title) { - return -1; - } else if (a.title > b.title) { - return 1; - } - - return 0; - }); - }; - - const foldersLinks = mapBy(folders, 'link'); - const foldersTitles = mapBy(folders, 'title'); - - // fetch details for each folder - return Promise.all(foldersLinks.map(getObjectDetails)).then((folderDetails) => { - // if attribute, just parse everything from what we've received - // and resolve. For metrics, lookup again each metric to get its - // identifier. If passing unsupported type, reject immediately. - if (type === 'attribute') { - // get all attributes, subtract what we have and add rest in unsorted folder - return getAttributes(projectId).then((attributes) => { - // get uris of attributes which are in some dimension folders - const attributesInFolders = []; - folderDetails.forEach((fd) => { - fd.dimension.content.attributes.forEach((attr) => { - attributesInFolders.push(attr.meta.uri); - }); - }); - // unsortedUris now contains uris of all attributes which aren't in a folder - const unsortedUris = - attributes - .filter(item => attributesInFolders.indexOf(item.link) === -1) - .map(item => item.link); - // now get details of attributes in no folders - return Promise.all(unsortedUris.map(getObjectDetails)) - .then((unsortedAttributeArgs) => { // TODO add map to r.json - // get unsorted attribute objects - const unsortedAttributes = unsortedAttributeArgs.map(attr => attr.attribute); - // create structure of folders with attributes - const structure = folderDetails.map((folderDetail) => { - return { - title: folderDetail.dimension.meta.title, - items: folderDetail.dimension.content.attributes - }; - }); - // and append "Unsorted" folder with attributes to the structure - structure.push({ - title: 'Unsorted', - items: unsortedAttributes + }; + + const foldersLinks = mapBy(folders, 'link'); + const foldersTitles = mapBy(folders, 'title'); + + // fetch details for each folder + return Promise.all(foldersLinks.map(getObjectDetails)).then((folderDetails) => { + // if attribute, just parse everything from what we've received + // and resolve. For metrics, lookup again each metric to get its + // identifier. If passing unsupported type, reject immediately. + if (type === 'attribute') { + // get all attributes, subtract what we have and add rest in unsorted folder + return getAttributes(projectId).then((attributes) => { + // get uris of attributes which are in some dimension folders + const attributesInFolders = []; + folderDetails.forEach((fd) => { + fd.dimension.content.attributes.forEach((attr) => { + attributesInFolders.push(attr.meta.uri); }); - sortFolderTree(structure); - - return structure; - }); - }); - } else if (type === 'metric') { - const entriesLinks = folderDetails.map(entry => mapBy(entry.folder.content.entries, 'link')); - // get all metrics, subtract what we have and add rest in unsorted folder - return getMetrics(projectId).then((metrics) => { - // get uris of metrics which are in some dimension folders - const metricsInFolders = []; - folderDetails.forEach((fd) => { - fd.folder.content.entries.forEach((metric) => { - metricsInFolders.push(metric.link); }); + // unsortedUris now contains uris of all attributes which aren't in a folder + const unsortedUris = + attributes + .filter(item => attributesInFolders.indexOf(item.link) === -1) + .map(item => item.link); + // now get details of attributes in no folders + return Promise.all(unsortedUris.map(getObjectDetails)) + .then((unsortedAttributeArgs) => { // TODO add map to r.json + // get unsorted attribute objects + const unsortedAttributes = unsortedAttributeArgs.map(attr => attr.attribute); + // create structure of folders with attributes + const structure = folderDetails.map((folderDetail) => { + return { + title: folderDetail.dimension.meta.title, + items: folderDetail.dimension.content.attributes + }; + }); + // and append "Unsorted" folder with attributes to the structure + structure.push({ + title: 'Unsorted', + items: unsortedAttributes + }); + sortFolderTree(structure); + + return structure; + }); }); - // unsortedUris now contains uris of all metrics which aren't in a folder - const unsortedUris = - metrics - .filter(item => metricsInFolders.indexOf(item.link) === -1) - .map(item => item.link); - - // sadly order of parameters of concat matters! (we want unsorted last) - entriesLinks.push(unsortedUris); - - // now get details of all metrics - return Promise.all(entriesLinks.map(linkArray => getMetricItemsDetails(linkArray))) - .then((tree) => { // TODO add map to r.json - // all promises resolved, i.e. details for each metric are available - const structure = tree.map((treeItems, idx) => { - // if idx is not in foldes list than metric is in "Unsorted" folder - return { - title: (foldersTitles[idx] || 'Unsorted'), - items: treeItems - }; + } else if (type === 'metric') { + const entriesLinks = folderDetails.map(entry => mapBy(entry.folder.content.entries, 'link')); + // get all metrics, subtract what we have and add rest in unsorted folder + return getMetrics(projectId).then((metrics) => { + // get uris of metrics which are in some dimension folders + const metricsInFolders = []; + folderDetails.forEach((fd) => { + fd.folder.content.entries.forEach((metric) => { + metricsInFolders.push(metric.link); }); - sortFolderTree(structure); - return structure; }); - }); - } + // unsortedUris now contains uris of all metrics which aren't in a folder + const unsortedUris = + metrics + .filter(item => metricsInFolders.indexOf(item.link) === -1) + .map(item => item.link); + + // sadly order of parameters of concat matters! (we want unsorted last) + entriesLinks.push(unsortedUris); + + // now get details of all metrics + return Promise.all(entriesLinks.map(linkArray => getMetricItemsDetails(linkArray))) + .then((tree) => { // TODO add map to r.json + // all promises resolved, i.e. details for each metric are available + const structure = tree.map((treeItems, idx) => { + // if idx is not in foldes list than metric is in "Unsorted" folder + return { + title: (foldersTitles[idx] || 'Unsorted'), + items: treeItems + }; + }); + sortFolderTree(structure); + return structure; + }); + }); + } - return Promise.reject(); + return Promise.reject(); + }); }); - }); -} - -/** - * Get identifier of a metadata object identified by its uri - * - * @method getObjectIdentifier - * @param uri uri of the metadata object for which the identifier is to be retrieved - * @return {String} object identifier - */ -export function getObjectIdentifier(uri) { - function idFinder(obj) { - if (obj.attribute) { - return obj.attribute.content.displayForms[0].meta.identifier; - } else if (obj.dimension) { - return obj.dimension.content.attributes.content.displayForms[0].meta.identifier; - } else if (obj.metric) { - return obj.metric.meta.identifier; - } - - throw Error('Unknown object!'); } - if (!isPlainObject(uri)) { - return getObjectDetails(uri).then(data => idFinder(data)); - } - return Promise.resolve(idFinder(uri)); -} + /** + * Get identifier of a metadata object identified by its uri + * + * @method getObjectIdentifier + * @param uri uri of the metadata object for which the identifier is to be retrieved + * @return {String} object identifier + */ + function getObjectIdentifier(uri) { + function idFinder(obj) { + if (obj.attribute) { + return obj.attribute.content.displayForms[0].meta.identifier; + } else if (obj.dimension) { + return obj.dimension.content.attributes.content.displayForms[0].meta.identifier; + } else if (obj.metric) { + return obj.metric.meta.identifier; + } -/** - * Get uri of an metadata object, specified by its identifier and project id it belongs to - * - * @method getObjectUri - * @param {string} projectId id of the project - * @param identifier identifier of the metadata object - * @return {String} uri of the metadata object - */ -export function getObjectUri(projectId, identifier) { - return ajax(`/gdc/md/${projectId}/identifiers`, { - method: 'POST', - body: { - identifierToUri: [identifier] + throw Error('Unknown object!'); } - }).then(parseJSON).then((data) => { - const found = data.identifiers.find(pair => pair.identifier === identifier); - if (found) { - return found.uri; + if (!isPlainObject(uri)) { + return getObjectDetails(uri).then(data => idFinder(data)); } + return Promise.resolve(idFinder(uri)); + } - throw new Error(`Object with identifier ${identifier} not found in project ${projectId}`); - }); -} + /** + * Get uri of an metadata object, specified by its identifier and project id it belongs to + * + * @method getObjectUri + * @param {string} projectId id of the project + * @param identifier identifier of the metadata object + * @return {String} uri of the metadata object + */ + function getObjectUri(projectId, identifier) { + return xhr.ajax(`/gdc/md/${projectId}/identifiers`, { + method: 'POST', + body: { + identifierToUri: [identifier] + } + }).then(xhr.parseJSON).then((data) => { + const found = data.identifiers.find(pair => pair.identifier === identifier); -/** - * Get uris specified by identifiers - * - * @method getUrisFromIdentifiers - * @param {String} projectId id of the project - * @param {Array} identifiers identifiers of the metadata objects - * @return {Array} array of identifier + uri pairs - */ -export function getUrisFromIdentifiers(projectId, identifiers) { - return post(`/gdc/md/${projectId}/identifiers`, { - body: { - identifierToUri: identifiers - } - }).then(parseJSON).then((data) => { - return data.identifiers; - }); -} + if (found) { + return found.uri; + } -/** - * Get identifiers specified by uris - * - * @method getIdentifiersFromUris - * @param {String} projectId id of the project - * @param {Array} uris of the metadata objects - * @return {Array} array of identifier + uri pairs - */ -export function getIdentifiersFromUris(projectId, uris) { - return post(`/gdc/md/${projectId}/identifiers`, { - body: { - uriToIdentifier: uris - } - }).then(parseJSON).then((data) => { - return data.identifiers; - }); -} + throw new Error(`Object with identifier ${identifier} not found in project ${projectId}`); + }); + } -/** - * Get attribute elements with their labels and uris. - * - * @param {String} projectId id of the project - * @param {String} labelUri uri of the label (display form) - * @param {Array} patterns elements labels/titles (for EXACT mode), or patterns (for WILD mode) - * @param {('EXACT'|'WILD')} mode match mode, currently only EXACT supported - * @return {Array} array of elementLabelUri objects - */ -export function translateElementLabelsToUris(projectId, labelUri, patterns, mode = 'EXACT') { - return post(`/gdc/md/${projectId}/labels`, { - body: { - elementLabelToUri: [ - { - labelUri, - mode, - patterns - } - ] - } - }).then(r => (r.ok ? r.json() : r)).then(r => _get(r, 'elementLabelUri')); -} + /** + * Get uris specified by identifiers + * + * @method getUrisFromIdentifiers + * @param {String} projectId id of the project + * @param {Array} identifiers identifiers of the metadata objects + * @return {Array} array of identifier + uri pairs + */ + function getUrisFromIdentifiers(projectId, identifiers) { + return xhr.post(`/gdc/md/${projectId}/identifiers`, { + body: { + identifierToUri: identifiers + } + }).then(xhr.parseJSON).then((data) => { + return data.identifiers; + }); + } -/** - * Get valid elements of an attribute, specified by its identifier and project id it belongs to - * - * @method getValidElements - * @param {string} projectId id of the project - * @param id display form identifier of the metadata object - * @param {Object} options objects with options: - * - limit {Number} - * - offset {Number} - * - order {String} 'asc' or 'desc' - * - filter {String} - * - prompt {String} - * - uris {Array} - * - complement {Boolean} - * - includeTotalCountWithoutFilters {Boolean} - * - restrictiveDefinition {String} - * @return {Object} ValidElements response with: - * - items {Array} elements - * - paging {Object} - * - elementsMeta {Object} - */ -export function getValidElements(projectId, id, options = {}) { - const query = pick(options, ['limit', 'offset', 'order', 'filter', 'prompt']); - const queryParams = queryString(query); - - const requestBody = pick(options, ['uris', 'complement', 'includeTotalCountWithoutFilters', 'restrictiveDefinition']); - return post(`/gdc/md/${projectId}/obj/${id}/validElements${queryParams}`.replace(/\?$/, ''), { - data: JSON.stringify({ - validElementsRequest: requestBody - }) - }).then(parseJSON); -} + /** + * Get identifiers specified by uris + * + * @method getIdentifiersFromUris + * @param {String} projectId id of the project + * @param {Array} uris of the metadata objects + * @return {Array} array of identifier + uri pairs + */ + function getIdentifiersFromUris(projectId, uris) { + return xhr.post(`/gdc/md/${projectId}/identifiers`, { + body: { + uriToIdentifier: uris + } + }).then(xhr.parseJSON).then((data) => { + return data.identifiers; + }); + } -/** - * Delete object - * - * @experimental - * @method deleteObject - * @param {String} uri of the object to be deleted - */ -export function deleteObject(uri) { - return del(uri); -} + /** + * Get attribute elements with their labels and uris. + * + * @param {String} projectId id of the project + * @param {String} labelUri uri of the label (display form) + * @param {Array} patterns elements labels/titles (for EXACT mode), or patterns (for WILD mode) + * @param {('EXACT'|'WILD')} mode match mode, currently only EXACT supported + * @return {Array} array of elementLabelUri objects + */ + function translateElementLabelsToUris(projectId, labelUri, patterns, mode = 'EXACT') { + return xhr.post(`/gdc/md/${projectId}/labels`, { + body: { + elementLabelToUri: [ + { + labelUri, + mode, + patterns + } + ] + } + }).then(r => (r.ok ? r.json() : r)).then(r => _get(r, 'elementLabelUri')); + } -/** - * Create object - * - * @experimental - * @method createObject - * @param {String} projectId - * @param {String} obj object definition - */ -export function createObject(projectId, obj) { - return post(`/gdc/md/${projectId}/obj?createAndGet=true`, { - data: JSON.stringify(obj) - }).then(parseJSON); -} + /** + * Get valid elements of an attribute, specified by its identifier and project id it belongs to + * + * @method getValidElements + * @param {string} projectId id of the project + * @param id display form id of the metadata object + * @param {Object} options objects with options: + * - limit {Number} + * - offset {Number} + * - order {String} 'asc' or 'desc' + * - filter {String} + * - prompt {String} + * - uris {Array} + * - complement {Boolean} + * - includeTotalCountWithoutFilters {Boolean} + * - restrictiveDefinition {String} + * @return {Object} ValidElements response with: + * - items {Array} elements + * - paging {Object} + * - elementsMeta {Object} + */ + function getValidElements(projectId, id, options = {}) { + const query = pick(options, ['limit', 'offset', 'order', 'filter', 'prompt']); + const queryParams = queryString(query); + + const requestBody = pick(options, ['uris', 'complement', 'includeTotalCountWithoutFilters', 'restrictiveDefinition']); + return xhr.post(`/gdc/md/${projectId}/obj/${id}/validElements${queryParams}`.replace(/\?$/, ''), { + data: JSON.stringify({ + validElementsRequest: requestBody + }) + }).then(xhr.parseJSON); + } -function isTaskFinished(task) { - const taskState = task.wTaskStatus.status; - return taskState === 'OK' || taskState === 'ERROR'; -} + /** + * Delete object + * + * @experimental + * @method deleteObject + * @param {String} uri of the object to be deleted + */ + function deleteObject(uri) { + return xhr.del(uri); + } -function checkStatusForError(response) { - if (response.wTaskStatus.status === 'ERROR') { - return Promise.reject(response); + /** + * Create object + * + * @experimental + * @method createObject + * @param {String} projectId + * @param {String} obj object definition + */ + function createObject(projectId, obj) { + return xhr.post(`/gdc/md/${projectId}/obj?createAndGet=true`, { + data: JSON.stringify(obj) + }).then(xhr.parseJSON); } - return response; -} -/** - * LDM manage - * - * @experimental - * @method ldmManage - * @param {String} projectId - * @param {String} maql - * @param {Object} options for polling (maxAttempts, pollStep) - */ -export function ldmManage(projectId, maql, options = {}) { - return post(`/gdc/md/${projectId}/ldm/manage2`, { - data: JSON.stringify({ - manage: { maql } + function isTaskFinished(task) { + const taskState = task.wTaskStatus.status; + return taskState === 'OK' || taskState === 'ERROR'; + } + + function checkStatusForError(response) { + if (response.wTaskStatus.status === 'ERROR') { + return Promise.reject(response); + } + return response; + } + + /** + * LDM manage + * + * @experimental + * @method ldmManage + * @param {String} projectId + * @param {String} maql + * @param {Object} options for polling (maxAttempts, pollStep) + */ + function ldmManage(projectId, maql, options = {}) { + return xhr.post(`/gdc/md/${projectId}/ldm/manage2`, { + data: JSON.stringify({ + manage: { maql } + }) }) - }) - .then(parseJSON) - .then((response) => { - const manageStatusUri = response.entries[0].link; - return handlePolling(manageStatusUri, isTaskFinished, options); - }) - .then(checkStatusForError); -} + .then(xhr.parseJSON) + .then((response) => { + const manageStatusUri = response.entries[0].link; + return handlePolling(xhr.get, manageStatusUri, isTaskFinished, options); + }) + .then(checkStatusForError); + } -/** - * ETL pull - * - * @experimental - * @method etlPull - * @param {String} projectId - * @param {String} uploadsDir - * @param {Object} options for polling (maxAttempts, pollStep) - */ -export function etlPull(projectId, uploadsDir, options = {}) { - return post(`/gdc/md/${projectId}/etl/pull2`, { - data: JSON.stringify({ - pullIntegration: uploadsDir + /** + * ETL pull + * + * @experimental + * @method etlPull + * @param {String} projectId + * @param {String} uploadsDir + * @param {Object} options for polling (maxAttempts, pollStep) + */ + function etlPull(projectId, uploadsDir, options = {}) { + return xhr.post(`/gdc/md/${projectId}/etl/pull2`, { + data: JSON.stringify({ + pullIntegration: uploadsDir + }) }) - }) - .then(parseJSON) - .then((response) => { - const etlPullStatusUri = response.pull2Task.links.poll; - return handlePolling(etlPullStatusUri, isTaskFinished, options); - }) - .then(checkStatusForError); + .then(xhr.parseJSON) + .then((response) => { + const etlPullStatusUri = response.pull2Task.links.poll; + return handlePolling(xhr.get, etlPullStatusUri, isTaskFinished, options); + }) + .then(checkStatusForError); + } + + return { + createObject, + deleteObject, + etlPull, + getAttributes, + getAvailableAttributes, + getAvailableFacts, + getAvailableMetrics, + getDimensions, + getFacts, + getFoldersWithItems, + getIdentifiersFromUris, + getMetrics, + getObjectDetails, + getObjectIdentifier, + getObjects, + getObjectsByQuery, + getObjectUri, + getObjectUsing, + getObjectUsingMany, + getUrisFromIdentifiers, + getValidElements, + getVisualizations, + ldmManage, + translateElementLabelsToUris + }; } diff --git a/src/project.js b/src/project.js index bed59512..74519513 100644 --- a/src/project.js +++ b/src/project.js @@ -1,5 +1,4 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. -import { post, ajax, del, get, put, parseJSON } from './xhr'; import { getIn, handlePolling } from './util'; /** @@ -9,49 +8,6 @@ import { getIn, handlePolling } from './util'; * @module project */ - -/** - * Get current project id - * - * @method getCurrentProjectId - * @return {String} current project identifier - */ -export function getCurrentProjectId() { - return get('/gdc/app/account/bootstrap').then((result) => { - const currentProject = result.bootstrapResource.current.project; - // handle situation in which current project is missing (e.g. new user) - if (!currentProject) { - return null; - } - - return result.bootstrapResource.current.project.links.self.split('/').pop(); - }); -} - -/** - * Fetches projects available for the user represented by the given profileId - * - * @method getProjects - * @param {String} profileId - User profile identifier - * @return {Array} An Array of projects - */ -export function getProjects(profileId) { - return get(`/gdc/account/profile/${profileId}/projects`).then((r) => { - return r.projects.map(p => p.project); - }); -} - -/** - * Fetches all datasets for the given project - * - * @method getDatasets - * @param {String} projectId - GD project identifier - * @return {Array} An array of objects containing datasets metadata - */ -export function getDatasets(projectId) { - return get(`/gdc/md/${projectId}/query/datasets`).then(getIn('query.entries')); -} - const DEFAULT_PALETTE = [ { r: 0x2b, g: 0x6b, b: 0xae }, { r: 0x69, g: 0xaa, b: 0x51 }, @@ -73,85 +29,6 @@ const DEFAULT_PALETTE = [ { r: 0xbf, g: 0xbf, b: 0xbf } ]; -/** - * Fetches a chart color palette for a project represented by the given - * projectId parameter. - * - * @method getColorPalette - * @param {String} projectId - A project identifier - * @return {Array} An array of objects with r, g, b fields representing a project's - * color palette - */ -export function getColorPalette(projectId) { - return get(`/gdc/projects/${projectId}/styleSettings`).then((result) => { - return result.styleSettings.chartPalette.map((c) => { - return { - r: c.fill.r, - g: c.fill.g, - b: c.fill.b - }; - }); - }, (err) => { - if (err.status === 200) { - return DEFAULT_PALETTE; - } - - throw new Error(err.statusText); - }); -} - -/** - * Sets given colors as a color palette for a given project. - * - * @method setColorPalette - * @param {String} projectId - GD project identifier - * @param {Array} colors - An array of colors that we want to use within the project. - * Each color should be an object with r, g, b fields. - */ -export function setColorPalette(projectId, colors) { - return put(`/gdc/projects/${projectId}/styleSettings`, { - data: { - styleSettings: { - chartPalette: colors.map((fill, idx) => { - return { fill, guid: `guid${idx}` }; - }) - } - } - }); -} - -/** - * Gets current timezone and its offset. Example output: - * - * { - * id: 'Europe/Prague', - * displayName: 'Central European Time', - * currentOffsetMs: 3600000 - * } - * - * @method getTimezone - * @param {String} projectId - GD project identifier - */ -export function getTimezone(projectId) { - const bootstrapUrl = `/gdc/app/account/bootstrap?projectId=${projectId}`; - - return get(bootstrapUrl).then((result) => { - return result.bootstrapResource.current.timezone; - }); -} - -export function setTimezone(projectId, timezone) { - const timezoneServiceUrl = `/gdc/md/${projectId}/service/timezone`; - const data = { - service: { timezone } - }; - - return ajax(timezoneServiceUrl, { - method: 'POST', - body: data - }).then(parseJSON); -} - const isProjectCreated = (project) => { const projectState = project.content.state; @@ -159,56 +36,191 @@ const isProjectCreated = (project) => { projectState === 'DELETED'; }; -/** - * Create project - * Note: returns a promise which is resolved when the project creation is finished - * - * @experimental - * @method createProject - * @param {String} title - * @param {String} authorizationToken - * @param {Object} options for project creation (summary, projectTemplate, ...) - * @return {Object} created project object - */ -export function createProject(title, authorizationToken, options = {}) { - const { - summary, - projectTemplate, - driver = 'Pg', - environment = 'TESTING', - guidedNavigation = 1 - } = options; - - return post('/gdc/projects', { - body: JSON.stringify({ - project: { - content: { - guidedNavigation, - driver, - authorizationToken, - environment - }, - meta: { - title, - summary, - projectTemplate +export function createModule(xhr) { + /** + * Get current project id + * + * @method getCurrentProjectId + * @return {String} current project identifier + */ + function getCurrentProjectId() { + return xhr.get('/gdc/app/account/bootstrap').then((result) => { + const currentProject = result.bootstrapResource.current.project; + // handle situation in which current project is missing (e.g. new user) + if (!currentProject) { + return null; + } + + return result.bootstrapResource.current.project.links.self.split('/').pop(); + }); + } + + /** + * Fetches projects available for the user represented by the given profileId + * + * @method getProjects + * @param {String} profileId - User profile identifier + * @return {Array} An Array of projects + */ + function getProjects(profileId) { + return xhr.get(`/gdc/account/profile/${profileId}/projects`).then((r) => { + return r.projects.map(p => p.project); + }); + } + + /** + * Fetches all datasets for the given project + * + * @method getDatasets + * @param {String} projectId - GD project identifier + * @return {Array} An array of objects containing datasets metadata + */ + function getDatasets(projectId) { + return xhr.get(`/gdc/md/${projectId}/query/datasets`).then(getIn('query.entries')); + } + + /** + * Fetches a chart color palette for a project represented by the given + * projectId parameter. + * + * @method getColorPalette + * @param {String} projectId - A project identifier + * @return {Array} An array of objects with r, g, b fields representing a project's + * color palette + */ + function getColorPalette(projectId) { + return xhr.get(`/gdc/projects/${projectId}/styleSettings`).then((result) => { + return result.styleSettings.chartPalette.map((c) => { + return { + r: c.fill.r, + g: c.fill.g, + b: c.fill.b + }; + }); + }, (err) => { + if (err.status === 200) { + return DEFAULT_PALETTE; + } + + throw new Error(err.statusText); + }); + } + + /** + * Sets given colors as a color palette for a given project. + * + * @method setColorPalette + * @param {String} projectId - GD project identifier + * @param {Array} colors - An array of colors that we want to use within the project. + * Each color should be an object with r, g, b fields. + */ + function setColorPalette(projectId, colors) { + return xhr.put(`/gdc/projects/${projectId}/styleSettings`, { + data: { + styleSettings: { + chartPalette: colors.map((fill, idx) => { + return { fill, guid: `guid${idx}` }; + }) } } + }); + } + + /** + * Gets current timezone and its offset. Example output: + * + * { + * id: 'Europe/Prague', + * displayName: 'Central European Time', + * currentOffsetMs: 3600000 + * } + * + * @method getTimezone + * @param {String} projectId - GD project identifier + */ + function getTimezone(projectId) { + const bootstrapUrl = `/gdc/app/account/bootstrap?projectId=${projectId}`; + + return xhr.get(bootstrapUrl).then((result) => { + return result.bootstrapResource.current.timezone; + }); + } + + function setTimezone(projectId, timezone) { + const timezoneServiceUrl = `/gdc/md/${projectId}/service/timezone`; + const data = { + service: { timezone } + }; + + return xhr.ajax(timezoneServiceUrl, { + method: 'POST', + body: data + }).then(xhr.parseJSON); + } + + /** + * Create project + * Note: returns a promise which is resolved when the project creation is finished + * + * @experimental + * @method createProject + * @param {String} title + * @param {String} authorizationToken + * @param {Object} options for project creation (summary, projectTemplate, ...) + * @return {Object} created project object + */ + function createProject(title, authorizationToken, options = {}) { + const { + summary, + projectTemplate, + driver = 'Pg', + environment = 'TESTING', + guidedNavigation = 1 + } = options; + + return xhr.post('/gdc/projects', { + body: JSON.stringify({ + project: { + content: { + guidedNavigation, + driver, + authorizationToken, + environment + }, + meta: { + title, + summary, + projectTemplate + } + } + }) }) - }) - .then(parseJSON) - .then(project => - handlePolling(project.uri, (response) => { - return isProjectCreated(response.project); - }, options)); -} - -/** - * Delete project - * - * @method deleteProject - * @param {String} projectId - */ -export function deleteProject(projectId) { - return del(`/gdc/projects/${projectId}`); + .then(xhr.parseJSON) + .then(project => + handlePolling(xhr.get, project.uri, (response) => { + return isProjectCreated(response.project); + }, options)); + } + + /** + * Delete project + * + * @method deleteProject + * @param {String} projectId + */ + function deleteProject(projectId) { + return xhr.del(`/gdc/projects/${projectId}`); + } + + return { + getCurrentProjectId, + getProjects, + getDatasets, + getColorPalette, + setColorPalette, + getTimezone, + setTimezone, + createProject, + deleteProject + }; } diff --git a/src/user.js b/src/user.js index 7978e12d..49b1cb74 100644 --- a/src/user.js +++ b/src/user.js @@ -1,134 +1,139 @@ // Copyright (C) 2007-2017, GoodData(R) Corporation. All rights reserved. -import { ajax, get, post, put, parseJSON } from './xhr'; -/** - * @module user - * @class user - */ +export function createModule(xhr) { + /** + * Find out whether a user is logged in + * + * @return {Promise} resolves with true if user logged in, false otherwise + * @method isLoggedIn + */ + function isLoggedIn() { + return new Promise((resolve, reject) => { + // cannot use get here directly - we need to access to response + // not to responses JSON get returns + xhr.ajax('/gdc/account/token', { method: 'GET' }).then((r) => { + if (r.ok) { + resolve(true); + } -/** - * Find out whether a user is logged in - * - * @return {Promise} resolves with true if user logged in, false otherwise - * @method isLoggedIn - */ -export function isLoggedIn() { - return new Promise((resolve, reject) => { - // cannot use get here directly - we need to access to response - // not to responses JSON get returns - ajax('/gdc/account/token', { method: 'GET' }).then((r) => { - if (r.ok) { - resolve(true); - } - - resolve(false); - }, (err) => { - if (err.response.status === 401) { resolve(false); - } else { - reject(err); - } + }, (err) => { + if (err.response.status === 401) { + resolve(false); + } else { + reject(err); + } + }); }); - }); -} + } + /** + * This function provides an authentication entry point to the GD API. It is needed to authenticate + * by calling this function prior any other API calls. After providing valid credentials + * every subsequent API call in a current session will be authenticated. + * + * @method login + * @param {String} username + * @param {String} password + */ + function login(username, password) { + return xhr.post('/gdc/account/login', { + body: JSON.stringify({ + postUserLogin: { + login: username, + password, + remember: 1, + captcha: '', + verifyCaptcha: '' + } + }) + }).then(xhr.parseJSON); + } -/** - * This function provides an authentication entry point to the GD API. It is needed to authenticate - * by calling this function prior any other API calls. After providing valid credentials - * every subsequent API call in a current session will be authenticated. - * - * @method login - * @param {String} username - * @param {String} password - */ -export function login(username, password) { - return post('/gdc/account/login', { - body: JSON.stringify({ - postUserLogin: { - login: username, - password, - remember: 1, - captcha: '', - verifyCaptcha: '' - } - }) - }).then(parseJSON); -} + /** + * This function provides an authentication entry point to the GD API via SSO + * https://help.gooddata.com/display/developer/GoodData+PGP+Single+Sign-On + * + * @method loginSso + * @param {String} sessionId PGP message + * @param {String} serverUrl + * @param {String} targetUrl + */ + function loginSso(sessionId, serverUrl, targetUrl) { + // cannot use xhr.get, server doesn't respond with JSON + return xhr.ajax(`/gdc/account/customerlogin?sessionId=${sessionId}&serverURL=${serverUrl}&targetURL=${targetUrl}`, { method: 'GET' }); + } -/** - * This function provides an authentication entry point to the GD API via SSO - * https://help.gooddata.com/display/developer/GoodData+PGP+Single+Sign-On - * - * @method loginSso - * @param {String} sessionId PGP message - * @param {String} serverUrl - * @param {String} targetUrl - */ -export function loginSso(sessionId, serverUrl, targetUrl) { - // cannot use xhr.get, server doesn't respond with JSON - return ajax(`/gdc/account/customerlogin?sessionId=${sessionId}&serverURL=${serverUrl}&targetURL=${targetUrl}`, { method: 'GET' }); -} + /** + * Logs out current user + * @method logout + */ + function logout() { + return isLoggedIn().then((loggedIn) => { + if (loggedIn) { + return xhr.get('/gdc/app/account/bootstrap').then((result) => { + const userUri = result.bootstrapResource.accountSetting.links.self; + const userId = userUri.match(/([^\/]+)\/?$/)[1]; // eslint-disable-line no-useless-escape -/** - * Logs out current user - * @method logout - */ -export function logout() { - return isLoggedIn().then((loggedIn) => { - if (loggedIn) { - return get('/gdc/app/account/bootstrap').then((result) => { - const userUri = result.bootstrapResource.accountSetting.links.self; - const userId = userUri.match(/([^\/]+)\/?$/)[1]; // eslint-disable-line no-useless-escape - - return ajax(`/gdc/account/login/${userId}`, { - method: 'delete' + return xhr.ajax(`/gdc/account/login/${userId}`, { + method: 'delete' + }); }); - }); - } + } - return Promise.resolve(); - }); -} + return Promise.resolve(); + }); + } -/** - * Updates user's profile settings - * @method updateProfileSettings - * @param {String} profileId - User profile identifier - * @param {Object} profileSetting -*/ -export function updateProfileSettings(profileId, profileSetting) { - return put(`/gdc/account/profile/${profileId}/settings`, { - data: profileSetting - }); -} + /** + * Updates user's profile settings + * @method updateProfileSettings + * @param {String} profileId - User profile identifier + * @param {Object} profileSetting + */ + function updateProfileSettings(profileId, profileSetting) { + return xhr.put(`/gdc/account/profile/${profileId}/settings`, { + data: profileSetting + }); + } -/** - * Returns info about currently logged in user from bootstrap resource - * @method getAccountInfo - */ -export function getAccountInfo() { - return get('/gdc/app/account/bootstrap') - .then((result) => { - const br = result.bootstrapResource; - const accountInfo = { - login: br.accountSetting.login, - loginMD5: br.current.loginMD5, - firstName: br.accountSetting.firstName, - lastName: br.accountSetting.lastName, - organizationName: br.settings.organizationName, - profileUri: br.accountSetting.links.self - }; + /** + * Returns info about currently logged in user from bootstrap resource + * @method getAccountInfo + */ + function getAccountInfo() { + return xhr.get('/gdc/app/account/bootstrap') + .then((result) => { + const br = result.bootstrapResource; + const accountInfo = { + login: br.accountSetting.login, + loginMD5: br.current.loginMD5, + firstName: br.accountSetting.firstName, + lastName: br.accountSetting.lastName, + organizationName: br.settings.organizationName, + profileUri: br.accountSetting.links.self + }; - return accountInfo; - }); -} + return accountInfo; + }); + } + + /** + * Returns the feature flags valid for the currently logged in user. + * @method getFeatureFlags + */ + function getFeatureFlags() { + return xhr.get('/gdc/app/account/bootstrap') + .then(result => result.bootstrapResource.current.featureFlags); + } -/** - * Returns the feature flags valid for the currently logged in user. - * @method getFeatureFlags - */ -export function getFeatureFlags() { - return get('/gdc/app/account/bootstrap') - .then(result => result.bootstrapResource.current.featureFlags); + return { + isLoggedIn, + login, + loginSso, + logout, + updateProfileSettings, + getAccountInfo, + getFeatureFlags + }; } diff --git a/src/util.js b/src/util.js index b4ddb11d..e53daba6 100644 --- a/src/util.js +++ b/src/util.js @@ -1,7 +1,6 @@ // Copyright (C) 2007-2017, GoodData(R) Corporation. All rights reserved. import { get } from 'lodash'; -import { get as xhrGet } from './xhr'; import { delay } from './utils/promise'; /** @@ -29,7 +28,7 @@ export const getIn = path => object => get(object, path); * @param {Object} options for polling (maxAttempts, pollStep) * @private */ -export const handlePolling = (uri, isPollingDone, options = {}) => { +export const handlePolling = (xhrGet, uri, isPollingDone, options = {}) => { const { attempts = 0, maxAttempts = 50, @@ -43,7 +42,7 @@ export const handlePolling = (uri, isPollingDone, options = {}) => { return isPollingDone(response) ? Promise.resolve(response) : delay(pollStep).then(() => { - return handlePolling(uri, isPollingDone, { + return handlePolling(xhrGet, uri, isPollingDone, { ...options, attempts: attempts + 1 }); diff --git a/src/utils/attributesMapLoader.js b/src/utils/attributesMapLoader.js index fbed4493..60ec1a04 100644 --- a/src/utils/attributesMapLoader.js +++ b/src/utils/attributesMapLoader.js @@ -3,10 +3,6 @@ import { set } from 'lodash'; -import { - getObjects -} from '../metadata'; - function getAttributeUris(displayForms) { return displayForms.map( displayForm => get(displayForm, ['attributeDisplayForm', 'content', 'formOf']) @@ -30,15 +26,17 @@ export function getMissingUrisInAttributesMap(displayFormsUris, attributesMap) { return uris.filter(uri => !attributesMap[uri]); } -export function loadAttributesMap(projectId, attributeDisplayFormUris) { - if (attributeDisplayFormUris.length === 0) { - return Promise.resolve({}); - } +export function createModule(md) { + return function loadAttributesMap(projectId, attributeDisplayFormUris) { + if (attributeDisplayFormUris.length === 0) { + return Promise.resolve({}); + } - return getObjects(projectId, attributeDisplayFormUris).then((displayForms) => { - const attributeUris = getAttributeUris(displayForms); - return getObjects(projectId, attributeUris).then((attributes) => { - return createAttributesMap(displayForms, attributes); + return md.getObjects(projectId, attributeDisplayFormUris).then((displayForms) => { + const attributeUris = getAttributeUris(displayForms); + return md.getObjects(projectId, attributeUris).then((attributes) => { + return createAttributesMap(displayForms, attributes); + }); }); - }); + }; } diff --git a/src/utils/testMock.js b/src/utils/testMock.js deleted file mode 100644 index add4b00c..00000000 --- a/src/utils/testMock.js +++ /dev/null @@ -1,17 +0,0 @@ -import fetchMock from 'fetch-mock'; -import * as config from '../../src/config'; - -export const mock = (...args) => { - const mocked = fetchMock.mock(...args); - config.setFetch(fetchMock.mockedContext.fetch); - - return mocked; -}; - -export const restore = () => { - fetchMock.restore(); -}; - -export const getMock = () => { - return fetchMock; -}; diff --git a/src/xhr.js b/src/xhr.js index 9219897b..1305a1b9 100644 --- a/src/xhr.js +++ b/src/xhr.js @@ -8,7 +8,6 @@ import { result } from 'lodash'; -import * as config from './config'; import fetch from './utils/fetch'; /** @@ -25,20 +24,6 @@ import fetch from './utils/fetch'; const DEFAULT_POLL_DELAY = 1000; -let tokenRequest; -let commonXhrSettings = {}; - -/** - * Back compatible method for setting common XHR settings - * - * Usually in our apps we used beforeSend ajax callback to set the X-GDC-REQUEST header with unique ID. - * - * @param settings object XHR settings as - */ -export function ajaxSetup(settings) { - commonXhrSettings = Object.assign({}, commonXhrSettings, settings); -} - function simulateBeforeSend(settings, url) { const xhr = { setRequestHeader(key, value) { @@ -66,75 +51,6 @@ function enrichSettingWithCustomDomain(originalUrl, originalSettings, domain) { return { url, settings }; } -function continueAfterTokenRequest(url, settings) { - return tokenRequest.then((response) => { - if (!response.ok) { - const err = new Error('Unauthorized'); - err.response = response; - throw err; - } - tokenRequest = null; - - return ajax(url, settings); // eslint-disable-line no-use-before-define - }, (reason) => { - tokenRequest = null; - return reason; - }); -} - -function createSettings(customSettings) { - const settings = merge( - { - headers: { - Accept: 'application/json; charset=utf-8', - 'Content-Type': 'application/json' - } - }, - commonXhrSettings, - customSettings - ); - - settings.pollDelay = (settings.pollDelay !== undefined) ? settings.pollDelay : DEFAULT_POLL_DELAY; - - // TODO jquery compat - add to warnings - settings.body = (settings.data) ? settings.data : settings.body; - settings.mode = 'same-origin'; - settings.credentials = 'same-origin'; - - if (isPlainObject(settings.body)) { - settings.body = JSON.stringify(settings.body); - } - - return settings; -} - -function handleUnauthorized(originalUrl, originalSettings) { - if (!tokenRequest) { - // Create only single token request for any number of waiting request. - // If token request exist, just listen for it's end. - const { url, settings } = enrichSettingWithCustomDomain('/gdc/account/token', createSettings({}), config.domain); - - tokenRequest = fetch(url, settings).then((response) => { - // tokenRequest = null; - // TODO jquery compat - allow to attach unauthorized callback and call it if attached - // if ((xhrObj.status === 401) && (isFunction(req.unauthorized))) { - // req.unauthorized(xhrObj, textStatus, err, deferred); - // return; - // } - // unauthorized handler is not defined or not http 401 - // unauthorized when retrieving token -> not logged - if (response.status === 401) { - const err = new Error('Unauthorized'); - err.response = response; - throw err; - } - - return response; - }); - } - return continueAfterTokenRequest(originalUrl, originalSettings); -} - function isLoginRequest(url) { return url.indexOf('/gdc/account/login') !== -1; } @@ -173,83 +89,176 @@ export function handlePolling(url, settings, sendRequest) { }); } -export function ajax(originalUrl, tempSettings = {}) { - const firstSettings = createSettings(tempSettings); - const { url, settings } = enrichSettingWithCustomDomain(originalUrl, firstSettings, config.domain); - - simulateBeforeSend(settings, url); +export function createModule(config) { + let commonXhrSettings = {}; + let tokenRequest; + + function createSettings(customSettings) { + const settings = merge( + { + headers: { + Accept: 'application/json; charset=utf-8', + 'Content-Type': 'application/json' + } + }, + commonXhrSettings, + customSettings + ); + + settings.pollDelay = (settings.pollDelay !== undefined) ? settings.pollDelay : DEFAULT_POLL_DELAY; + + // TODO jquery compat - add to warnings + settings.body = (settings.data) ? settings.data : settings.body; + settings.mode = 'same-origin'; + settings.credentials = 'same-origin'; + + if (isPlainObject(settings.body)) { + settings.body = JSON.stringify(settings.body); + } - if (tokenRequest) { - return continueAfterTokenRequest(url, settings); + return settings; + } + /** + * Back compatible method for setting common XHR settings + * + * Usually in our apps we used beforeSend ajax callback to set the X-GDC-REQUEST header with unique ID. + * + * @param settings object XHR settings as + */ + function ajaxSetup(settings) { + commonXhrSettings = Object.assign({}, commonXhrSettings, settings); } - return fetch(url, settings).then((response) => { - // If response.status id 401 and it was a login request there is no need - // to cycle back for token - login does not need token and this meant you - // are not authorized - if (response.status === 401) { - if (isLoginRequest(url)) { + function continueAfterTokenRequest(url, settings) { + return tokenRequest.then((response) => { + if (!response.ok) { const err = new Error('Unauthorized'); err.response = response; throw err; } + tokenRequest = null; + + return ajax(url, settings); // eslint-disable-line no-use-before-define + }, (reason) => { + tokenRequest = null; + return reason; + }); + } - return handleUnauthorized(url, settings); + function handleUnauthorized(originalUrl, originalSettings) { + if (!tokenRequest) { + // Create only single token request for any number of waiting request. + // If token request exist, just listen for it's end. + const { url, settings } = enrichSettingWithCustomDomain('/gdc/account/token', createSettings({}), config.getDomain()); + + tokenRequest = fetch(url, settings).then((response) => { + // tokenRequest = null; + // TODO jquery compat - allow to attach unauthorized callback and call it if attached + // if ((xhrObj.status === 401) && (isFunction(req.unauthorized))) { + // req.unauthorized(xhrObj, textStatus, err, deferred); + // return; + // } + // unauthorized handler is not defined or not http 401 + // unauthorized when retrieving token -> not logged + if (response.status === 401) { + const err = new Error('Unauthorized'); + err.response = response; + throw err; + } + + return response; + }); } + return continueAfterTokenRequest(originalUrl, originalSettings); + } + + function ajax(originalUrl, tempSettings = {}) { + const firstSettings = createSettings(tempSettings); + const { url, settings } = enrichSettingWithCustomDomain(originalUrl, firstSettings, config.getDomain()); - if (response.status === 202 && !settings.dontPollOnResult) { - // poll on new provided url, fallback to the original one - // (for example validElements returns 303 first with new url which may then return 202 to poll on) - let finalUrl = response.url || url; + simulateBeforeSend(settings, url); - const finalSettings = settings; + if (tokenRequest) { + return continueAfterTokenRequest(url, settings); + } - // if the response is 202 and Location header is not empty, let's poll on the new Location - if (response.headers.has('Location')) { - finalUrl = response.headers.get('Location'); + return fetch(url, settings).then((response) => { + // If response.status id 401 and it was a login request there is no need + // to cycle back for token - login does not need token and this meant you + // are not authorized + if (response.status === 401) { + if (isLoginRequest(url)) { + const err = new Error('Unauthorized'); + err.response = response; + throw err; + } + + return handleUnauthorized(url, settings); } - finalSettings.method = 'GET'; - delete finalSettings.data; - delete finalSettings.body; - return handlePolling(finalUrl, finalSettings, ajax); - } - return response; - }).then(checkStatus); -} + if (response.status === 202 && !settings.dontPollOnResult) { + // poll on new provided url, fallback to the original one + // (for example validElements returns 303 first with new url which may then return 202 to poll on) + let finalUrl = response.url || url; -function xhrMethod(method) { - return function methodFn(url, settings) { - const opts = merge({ method }, settings); + const finalSettings = settings; - return ajax(url, opts); - }; -} + // if the response is 202 and Location header is not empty, let's poll on the new Location + if (response.headers.has('Location')) { + finalUrl = response.headers.get('Location'); + } + finalSettings.method = 'GET'; + delete finalSettings.data; + delete finalSettings.body; -/** - * Wrapper for xhr.ajax method GET - * @method get - */ -export const get = (url, settings) => { - const opts = merge({ method: 'GET' }, settings); + return handlePolling(finalUrl, finalSettings, ajax); + } + return response; + }).then(checkStatus); + } - return ajax(url, opts).then(parseJSON); -}; + /** + * Wrapper for xhr.ajax method GET + * @method get + */ + const get = (url, settings) => { + const opts = merge({ method: 'GET' }, settings); + return ajax(url, opts).then(parseJSON); + }; -/** - * Wrapper for xhr.ajax method POST - * @method post - */ -export const post = xhrMethod('POST'); + function xhrMethod(method) { + return function methodFn(url, settings) { + const opts = merge({ method }, settings); -/** - * Wrapper for xhr.ajax method PUT - * @method put - */ -export const put = xhrMethod('PUT'); + return ajax(url, opts); + }; + } -/** - * Wrapper for xhr.ajax method DELETE - * @method delete - */ -export const del = xhrMethod('DELETE'); + /** + * Wrapper for xhr.ajax method POST + * @method post + */ + const post = xhrMethod('POST'); + + /** + * Wrapper for xhr.ajax method PUT + * @method put + */ + const put = xhrMethod('PUT'); + + /** + * Wrapper for xhr.ajax method DELETE + * @method delete + */ + const del = xhrMethod('DELETE'); + + return { + get, + post, + put, + del, + ajax, + ajaxSetup, + parseJSON + }; +} diff --git a/test/admin/clients.test.js b/test/admin/clients.test.js index 150958c2..6fdaa796 100644 --- a/test/admin/clients.test.js +++ b/test/admin/clients.test.js @@ -1,8 +1,14 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetchMock from '../utils/fetch-mock'; -import * as clients from '../../src/admin/clients'; +import { createModule as clientsFactory } from '../../src/admin/clients'; +import { createModule as xhrFactory } from '../../src/xhr'; +import { createModule as configFactory } from '../../src/config'; -describe('project', () => { +const config = configFactory(); +const xhr = xhrFactory(config); +const clients = clientsFactory(xhr); + +describe('clients', () => { describe('with fake server', () => { afterEach(() => { fetchMock.restore(); diff --git a/test/admin/contracts.test.js b/test/admin/contracts.test.js index c1b2e417..6c072216 100644 --- a/test/admin/contracts.test.js +++ b/test/admin/contracts.test.js @@ -1,6 +1,12 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetchMock from '../utils/fetch-mock'; -import * as contracts from '../../src/admin/contracts'; +import { createModule as contractsFactory } from '../../src/admin/contracts'; +import { createModule as xhrFactory } from '../../src/xhr'; +import { createModule as configFactory } from '../../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const contracts = contractsFactory(xhr); describe('contracts', () => { describe('with fake server', () => { diff --git a/test/admin/dataProducts.test.js b/test/admin/dataProducts.test.js index 6e8da87e..473f2f16 100644 --- a/test/admin/dataProducts.test.js +++ b/test/admin/dataProducts.test.js @@ -1,6 +1,12 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetchMock from '../utils/fetch-mock'; -import * as dataProducts from '../../src/admin/dataProducts'; +import { createModule as dataProductsFactory } from '../../src/admin/dataProducts'; +import { createModule as xhrFactory } from '../../src/xhr'; +import { createModule as configFactory } from '../../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const dataProducts = dataProductsFactory(xhr); describe('dataProducts', () => { describe('with fake server', () => { @@ -91,8 +97,7 @@ describe('dataProducts', () => { } }) } - ) - ; + ); return dataProducts.getDataProducts('contractId', '').then((result) => { expect(result.items.length).toBe(2); expect(result.items[0].domains[0].name).toBe('data-admin-test1'); diff --git a/test/admin/domainDataProducts.test.js b/test/admin/domainDataProducts.test.js index 04542191..e1ae01c1 100644 --- a/test/admin/domainDataProducts.test.js +++ b/test/admin/domainDataProducts.test.js @@ -1,6 +1,12 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetchMock from '../utils/fetch-mock'; -import * as domaindataproducts from '../../src/admin/domainDataProducts'; +import { createModule as domainDataproductsFactory } from '../../src/admin/domainDataProducts'; +import { createModule as xhrFactory } from '../../src/xhr'; +import { createModule as configFactory } from '../../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const domainDataproducts = domainDataproductsFactory(xhr); describe('domainDataProducts', () => { describe('with fake server', () => { @@ -15,7 +21,7 @@ describe('domainDataProducts', () => { 400 ); - return domaindataproducts.getDomainDataProducts('contractId', 'dataProductId').then(null, err => expect(err).toBeInstanceOf(Error)); + return domainDataproducts.getDomainDataProducts('contractId', 'dataProductId').then(null, err => expect(err).toBeInstanceOf(Error)); }); it('should return domaindataproducts', () => { @@ -44,7 +50,7 @@ describe('domainDataProducts', () => { }) } ); - return domaindataproducts.getDomainDataProducts('contractId', 'dataProductId').then((result) => { + return domainDataproducts.getDomainDataProducts('contractId', 'dataProductId').then((result) => { expect(result.items.length).toBe(1); expect(result.items[0].domain.name).toBe('data-admin-test1'); expect(result.items[0].domain.environment).toBe('TEST'); diff --git a/test/admin/domainSegments.test.js b/test/admin/domainSegments.test.js index 4fcb3053..04f0299f 100644 --- a/test/admin/domainSegments.test.js +++ b/test/admin/domainSegments.test.js @@ -1,6 +1,12 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetchMock from '../utils/fetch-mock'; -import * as domainSegments from '../../src/admin/domainSegments'; +import { createModule as domainSegmentsFactory } from '../../src/admin/domainSegments'; +import { createModule as xhrFactory } from '../../src/xhr'; +import { createModule as configFactory } from '../../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const domainSegments = domainSegmentsFactory(xhr); describe('domainSegments', () => { describe('with fake server', () => { diff --git a/test/admin/domains.test.js b/test/admin/domains.test.js index 06c5c898..d4752f49 100644 --- a/test/admin/domains.test.js +++ b/test/admin/domains.test.js @@ -1,6 +1,12 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetchMock from '../utils/fetch-mock'; -import * as domains from '../../src/admin/domains'; +import { createModule as domainsFactory } from '../../src/admin/domains'; +import { createModule as xhrFactory } from '../../src/xhr'; +import { createModule as configFactory } from '../../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const domains = domainsFactory(xhr); describe('project', () => { describe('with fake server', () => { diff --git a/test/admin/segments.test.js b/test/admin/segments.test.js index bdd82718..0c99a5a7 100644 --- a/test/admin/segments.test.js +++ b/test/admin/segments.test.js @@ -1,6 +1,12 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetchMock from '../utils/fetch-mock'; -import * as segments from '../../src/admin/segments'; +import { createModule as segmentsFactory } from '../../src/admin/segments'; +import { createModule as xhrFactory } from '../../src/xhr'; +import { createModule as configFactory } from '../../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const segments = segmentsFactory(xhr); describe('segments', () => { describe('with fake server', () => { diff --git a/test/catalogue.test.js b/test/catalogue.test.js index c6fd1afc..8aeef0ad 100644 --- a/test/catalogue.test.js +++ b/test/catalogue.test.js @@ -1,7 +1,17 @@ import { cloneDeep, get } from 'lodash'; import fetchMock from './utils/fetch-mock'; import * as fixtures from './fixtures/catalogue'; -import * as catalogue from '../src/catalogue'; +import { createModule as catalogueFactory } from '../src/catalogue'; +import { createModule as xhrFactory } from '../src/xhr'; +import { createModule as executionFactory } from '../src/execution'; +import { createModule as mdFactory } from '../src/metadata'; +import { createModule as configFactory } from '../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const md = mdFactory(xhr); +const execution = executionFactory(xhr, md); +const catalogue = catalogueFactory(xhr, execution); describe('Catalogue', () => { const projectId = 'some_id'; diff --git a/test/config.test.js b/test/config.test.js index 7db0d14b..b2e70351 100644 --- a/test/config.test.js +++ b/test/config.test.js @@ -1,28 +1,30 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. -import * as config from '../src/config'; +import { createModule } from '../src/config'; + +const config = createModule(); describe('config', () => { describe('setCustomDomain', () => { afterEach(() => { - config.domain = undefined; + config.setCustomDomain(null); }); it('should set url if valid', () => { config.setCustomDomain('https://custom.domain.tld/'); - expect(config.domain).toBe('https://custom.domain.tld'); + expect(config.getDomain()).toBe('https://custom.domain.tld'); config.setCustomDomain('custom.domain.tld'); - expect(config.domain).toBe('https://custom.domain.tld'); + expect(config.getDomain()).toBe('https://custom.domain.tld'); config.setCustomDomain('www.domain.tld'); - expect(config.domain).toBe('https://www.domain.tld'); + expect(config.getDomain()).toBe('https://www.domain.tld'); }); it('should strip trailing uri', () => { config.setCustomDomain('https://custom.domain.tld/'); - expect(config.domain).toBe('https://custom.domain.tld'); + expect(config.getDomain()).toBe('https://custom.domain.tld'); }); it('should strip trailing whitespace', () => { config.setCustomDomain(' https://custom.domain.tld/ \n'); - expect(config.domain).toBe('https://custom.domain.tld'); + expect(config.getDomain()).toBe('https://custom.domain.tld'); }); it('should throw with invalid url', () => { expect(() => { @@ -31,7 +33,7 @@ describe('config', () => { }); it('should unset domain with null argument', () => { config.setCustomDomain(null); - expect(config.domain).toBe(undefined); + expect(config.getDomain()).toBe(undefined); }); it('should unset domain only with null argument', () => { expect(() => { diff --git a/test/execution/execute-afm.test.js b/test/execution/execute-afm.test.js index 049137ac..8c4fc4bf 100644 --- a/test/execution/execute-afm.test.js +++ b/test/execution/execute-afm.test.js @@ -1,6 +1,12 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetchMock from '../utils/fetch-mock'; -import executeAfm, { nextPageOffset, mergePageData } from '../../src/execution/execute-afm'; +import { createModule as executeAfmFactory, nextPageOffset, mergePageData } from '../../src/execution/execute-afm'; +import { createModule as xhrFactory } from '../../src/xhr'; +import { createModule as configFactory } from '../../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const executeAfm = executeAfmFactory(xhr); describe('nextPageOffset', () => { it('should work for 1 dimension', () => { diff --git a/test/execution/experimental-executions.test.js b/test/execution/experimental-executions.test.js index 04fc84f1..70d9a27d 100644 --- a/test/execution/experimental-executions.test.js +++ b/test/execution/experimental-executions.test.js @@ -3,8 +3,18 @@ import { cloneDeep, range } from 'lodash'; import fetchMock from '../utils/fetch-mock'; -import * as ex from '../../src/execution/experimental-executions'; import { expectColumns, expectMetricDefinition } from '../helpers/execution'; +import { createModule as exFactory } from '../../src/execution/experimental-executions'; +import { createModule as attributesMapLoaderFactory } from '../../src/utils/attributesMapLoader'; +import { createModule as xhrFactory } from '../../src/xhr'; +import { createModule as mdFactory } from '../../src/metadata'; +import { createModule as configFactory } from '../../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const md = mdFactory(xhr); +const attributesMapLoader = attributesMapLoaderFactory(md); +const ex = exFactory(xhr, attributesMapLoader); describe('execution', () => { describe('with fake server', () => { @@ -231,7 +241,7 @@ describe('execution', () => { isPoP: undefined }); }).catch(() => { - expect().fail('Should not fail when processing mappings'); + throw new Error('Should not fail when processing mappings'); }); }); diff --git a/test/gooddata.test.js b/test/gooddata.test.js new file mode 100644 index 00000000..802c4da7 --- /dev/null +++ b/test/gooddata.test.js @@ -0,0 +1,67 @@ +// Copyright (C) 2007-2017, GoodData(R) Corporation. All rights reserved. +import defaultSdk, { factory } from '../src/gooddata'; +import fetchMock from './utils/fetch-mock'; + +const modules = [ + 'catalogue', + 'config', + 'md', + 'project', + 'user', + 'xhr' +]; + +describe('factory', () => { + afterEach(() => { + fetchMock.restore(); + }); + + it('should create default instance with default import', () => { + defaultSdk.config.setCustomDomain('secure.gooddata.com'); + fetchMock.mock('https://secure.gooddata.com/some/url', { status: 200, body: 'hello from secure' }); + + return defaultSdk.xhr.ajax('/some/url').then((response) => { + expect(response.status).toBe(200); + return response.text(); + }).then((body) => { + expect(body).toBe('hello from secure'); + }); + }); + + it('should create instance of SDK', () => { + const sdk = factory(); + fetchMock.mock('/some/url', { status: 200, body: 'hello' }); + + modules.forEach(m => expect(sdk).toHaveProperty(m)); + + return sdk.xhr.ajax('/some/url').then((response) => { + expect(response.status).toBe(200); + return response.text(); + }).then((body) => { + expect(body).toBe('hello'); + }); + }); + + it('should create instances with custom domains', () => { + const sdkStg3 = factory({ domain: 'staging3.intgdc.com' }); + const sdkStg2 = factory({ domain: 'staging2.intgdc.com' }); + + expect(sdkStg3.config.getDomain()).toEqual('https://staging3.intgdc.com'); + expect(sdkStg2.config.getDomain()).toEqual('https://staging2.intgdc.com'); + fetchMock.mock('https://staging3.intgdc.com/some/url', { status: 200, body: 'hello from stg3' }); + fetchMock.mock('https://staging2.intgdc.com/some/url', { status: 200, body: 'hello from stg2' }); + + return Promise.all([ + sdkStg3.xhr.ajax('/some/url') + .then(r => r.text()) + .then((body) => { + expect(body).toEqual('hello from stg3'); + }), + sdkStg2.xhr.ajax('/some/url') + .then(r => r.text()) + .then((body) => { + expect(body).toEqual('hello from stg2'); + }) + ]); + }); +}); diff --git a/test/metadata.test.js b/test/metadata.test.js index 88895a69..46ff3392 100644 --- a/test/metadata.test.js +++ b/test/metadata.test.js @@ -2,10 +2,15 @@ import { range, find } from 'lodash'; import fetchMock from './utils/fetch-mock'; import { mockPollingRequest } from './helpers/polling'; -import * as md from '../src/metadata'; -import * as xhr from '../src/xhr'; +import { createModule as mdFactory } from '../src/metadata'; +import { createModule as xhrFactory } from '../src/xhr'; +import { createModule as configFactory } from '../src/config'; import * as fixtures from './fixtures/metadata'; +const config = configFactory(); +const xhr = xhrFactory(config); +const md = mdFactory(xhr); + describe('metadata', () => { describe('with fake server', () => { afterEach(() => { @@ -199,7 +204,7 @@ describe('metadata', () => { ); return md.etlPull('1', '1').then(() => { - expect().fail('Should reject the promise if task ends with error'); + throw new Error('Should reject the promise if task ends with error'); }, (err) => { expect(err).toBeInstanceOf(Error); }); @@ -258,7 +263,7 @@ describe('metadata', () => { ); return md.ldmManage('1', '1').then(() => { - expect().fail('Should reject the promise if task ends with error'); + throw new Error('Should reject the promise if task ends with error'); }, (err) => { expect(err).toBeInstanceOf(Error); }); @@ -535,7 +540,7 @@ describe('metadata', () => { describe('translateElementLabelsToUris', () => { it('should return two label uris', () => { fetchMock.post( - '/gdc/md/myFakeProjectId/labels', + '/gdc/md/myFakeProjectId/labels', { status: 200, body: JSON.stringify(fixtures.elementsLabelsResult) @@ -651,7 +656,7 @@ describe('metadata', () => { ); return md.getObjectUsing(projectId, object, { types }).then(() => { - expect().fail('Should reject the promise on 400 response'); + throw new Error('Should reject the promise on 400 response'); }).catch((err) => { expect(err.response.status).toBe(400); }); @@ -689,7 +694,7 @@ describe('metadata', () => { }); it('should load objects dependencies', () => { - fetchMock.mock( + fetchMock.post( using2Uri, { status: 200, body: JSON.stringify({ useMany: response }) } ); @@ -736,7 +741,7 @@ describe('metadata', () => { ); return md.getObjectUsingMany(projectId, objects, { types }).then(() => { - expect().fail('Should reject the promise on 400 response'); + throw new Error('Should reject the promise on 400 response'); }).catch((err) => { expect(err.response.status).toBe(400); }); @@ -837,7 +842,7 @@ describe('metadata', () => { ); return md.getObjects(projectId, uris).then(() => { - expect().fail('Should reject the promise on 400 response'); + throw new Error('Should reject the promise on 400 response'); }).catch((err) => { expect(err.response.status).toBe(400); }); @@ -850,11 +855,11 @@ describe('metadata', () => { const attributeId = 'attribute.id'; const uri = `/gdc/md/${projectId}/obj/${attributeId}/validElements`; - beforeEach(() => { // eslint-disable-line mocha/no-hooks-for-single-case + beforeEach(() => { postSpy = jest.spyOn(xhr, 'post'); }); - afterEach(() => { // eslint-disable-line mocha/no-hooks-for-single-case + afterEach(() => { postSpy.mockRestore(); }); diff --git a/test/project.test.js b/test/project.test.js index 66650033..b2c49f15 100644 --- a/test/project.test.js +++ b/test/project.test.js @@ -1,7 +1,13 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetchMock from './utils/fetch-mock'; import { mockPollingRequest } from './helpers/polling'; -import * as project from '../src/project'; +import { createModule as projectFactory } from '../src/project'; +import { createModule as xhrFactory } from '../src/xhr'; +import { createModule as configFactory } from '../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const project = projectFactory(xhr); describe('project', () => { describe('with fake server', () => { @@ -23,7 +29,7 @@ describe('project', () => { { status: 200, body: JSON.stringify({ projects: [{ project: { meta: { title: 'p1' } } }, - { project: { meta: { title: 'p2' } } }] }) + { project: { meta: { title: 'p2' } } }] }) } ); return project.getProjects('myProfileId').then((result) => { @@ -270,9 +276,9 @@ describe('project', () => { mockPollingRequest(projectUri, pendingProject, createdProject); - const config = { pollStep: 1, maxAttempts: 1 }; - return project.createProject('Project', '1234', config).then(() => { - expect().fail('Should reject the promise if create project ended with 400'); + const options = { pollStep: 1, maxAttempts: 1 }; + return project.createProject('Project', '1234', options).then(() => { + throw new Error('Should reject the promise if create project ended with 400'); }, (err) => { expect(err).toBeInstanceOf(Error); }); @@ -290,7 +296,7 @@ describe('project', () => { ); return project.createProject('Project', '1234').then(() => { - expect().fail('Should reject the promise if create project ended with 400'); + throw new Error('Should reject the promise if create project ended with 400'); }, (err) => { expect(err).toBeInstanceOf(Error); }); diff --git a/test/user.test.js b/test/user.test.js index 93984a15..4ebae5a3 100644 --- a/test/user.test.js +++ b/test/user.test.js @@ -1,6 +1,12 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. import fetchMock from './utils/fetch-mock'; -import * as user from '../src/user'; +import { createModule as userFactory } from '../src/user'; +import { createModule as xhrFactory } from '../src/xhr'; +import { createModule as configFactory } from '../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); +const user = userFactory(xhr); describe('user', () => { describe('with fake server', () => { @@ -68,7 +74,7 @@ describe('user', () => { 400 ); return user.loginSso(sessionId, serverUrl, targetUrl).then(() => { - expect().fail('Should reject with 400'); + throw new Error('Should reject with 400'); }, (err) => { expect(err.response.status).toBe(400); }); @@ -147,7 +153,7 @@ describe('user', () => { { status: 400, body: '' } ); return user.updateProfileSettings(userId, []).then(() => { - expect().fail('Should reject with 400'); + throw new Error('Should reject with 400'); }, (err) => { expect(err.response.status).toBe(400); }); diff --git a/test/utils/attributesMapLoader.test.js b/test/utils/attributesMapLoader.test.js index 28778473..35d85f4d 100644 --- a/test/utils/attributesMapLoader.test.js +++ b/test/utils/attributesMapLoader.test.js @@ -1,11 +1,15 @@ -import { - loadAttributesMap, - getMissingUrisInAttributesMap -} from '../../src/utils/attributesMapLoader'; - import fetchMock from './fetch-mock'; +import { createModule as attributesMapLoaderFactory, getMissingUrisInAttributesMap } from '../../src/utils/attributesMapLoader'; +import { createModule as xhrFactory } from '../../src/xhr'; +import { createModule as mdFactory } from '../../src/metadata'; +import { createModule as configFactory } from '../../src/config'; import * as fixtures from '../fixtures/attributesMapLoader'; +const config = configFactory(); +const xhr = xhrFactory(config); +const md = mdFactory(xhr); +const loadAttributesMap = attributesMapLoaderFactory(md); + describe('loadAttributesMap', () => { const projectId = 'mockProject'; diff --git a/test/xhr.test.js b/test/xhr.test.js index 2138e3ea..efe405c0 100644 --- a/test/xhr.test.js +++ b/test/xhr.test.js @@ -1,8 +1,11 @@ // Copyright (C) 2007-2013, GoodData(R) Corporation. All rights reserved. import fetchMock from './utils/fetch-mock'; -import * as xhr from '../src/xhr'; -import { setCustomDomain } from '../src/config'; +import { createModule as xhrFactory, handlePolling } from '../src/xhr'; +import { createModule as configFactory } from '../src/config'; + +const config = configFactory(); +const xhr = xhrFactory(config); describe('fetch', () => { afterEach(() => { @@ -32,7 +35,7 @@ describe('fetch', () => { it('should handle unsuccessful request', () => { fetchMock.mock('/some/url', 404); return xhr.ajax('/some/url').then(() => { - expect().fail('should be rejected'); + throw new Error('should be rejected'); }, (err) => { expect(err.response.status).toBe(404); }); @@ -62,7 +65,7 @@ describe('fetch', () => { return 200; }) - .mock('/gdc/account/token', 200); + .mock('/gdc/account/token', 200); return xhr.ajax('/some/url').then((r) => { expect(r.status).toBe(200); }); @@ -70,7 +73,7 @@ describe('fetch', () => { it('should fail if token renewal fails', () => { fetchMock.mock('/some/url', 401) - .mock('/gdc/account/token', 401); + .mock('/gdc/account/token', 401); return xhr.ajax('/some/url').then(null, (err) => { expect(err.response.status).toBe(401); }); @@ -86,8 +89,8 @@ describe('fetch', () => { }; fetchMock.mock('/some/url/1', firstFailedMatcher) - .mock('/some/url/2', firstFailedMatcher) - .mock('/gdc/account/token', 200); + .mock('/some/url/2', firstFailedMatcher) + .mock('/gdc/account/token', 200); return Promise.all([xhr.ajax('/some/url/1'), xhr.ajax('/some/url/2')]).then((r) => { expect(r[0].status).toBe(200); @@ -106,7 +109,7 @@ describe('fetch', () => { const handleRequest = jest.fn(() => Promise.resolve()); - const promise = xhr.handlePolling('/some/url', { pollDelay: () => 1000 }, handleRequest); + const promise = handlePolling('/some/url', { pollDelay: () => 1000 }, handleRequest); jest.runTimersToTime(1000); // ms @@ -278,12 +281,12 @@ describe('fetch', () => { describe('enrichSettingWithCustomDomain', () => { afterEach(() => { - setCustomDomain(null); + config.setCustomDomain(null); }); it('should not touch settings if no domain set', () => { fetchMock.mock('/test1', 200); - expect(() => setCustomDomain()).toThrow(); + expect(() => config.setCustomDomain()).toThrow(); xhr.ajax('/test1'); @@ -294,7 +297,7 @@ describe('fetch', () => { }); it('should add domain before url', () => { - setCustomDomain('https://domain.tld'); + config.setCustomDomain('https://domain.tld'); fetchMock.mock('https://domain.tld/test1', 200); xhr.ajax('https://domain.tld/test1'); @@ -306,7 +309,7 @@ describe('fetch', () => { }); it('should not double domain in settings url', () => { - setCustomDomain('https://domain.tld'); + config.setCustomDomain('https://domain.tld'); fetchMock.mock('https://domain.tld/test1', 200); xhr.ajax('https://domain.tld/test1'); diff --git a/yarn.lock b/yarn.lock index 92b691c3..f7dc424b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,58 @@ # yarn lockfile v1 +"@babel/code-frame@7.0.0-beta.36": + version "7.0.0-beta.36" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.36.tgz#2349d7ec04b3a06945ae173280ef8579b63728e4" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/helper-function-name@7.0.0-beta.36": + version "7.0.0-beta.36" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.36.tgz#366e3bc35147721b69009f803907c4d53212e88d" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.36" + "@babel/template" "7.0.0-beta.36" + "@babel/types" "7.0.0-beta.36" + +"@babel/helper-get-function-arity@7.0.0-beta.36": + version "7.0.0-beta.36" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.36.tgz#f5383bac9a96b274828b10d98900e84ee43e32b8" + dependencies: + "@babel/types" "7.0.0-beta.36" + +"@babel/template@7.0.0-beta.36": + version "7.0.0-beta.36" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.36.tgz#02e903de5d68bd7899bce3c5b5447e59529abb00" + dependencies: + "@babel/code-frame" "7.0.0-beta.36" + "@babel/types" "7.0.0-beta.36" + babylon "7.0.0-beta.36" + lodash "^4.2.0" + +"@babel/traverse@7.0.0-beta.36": + version "7.0.0-beta.36" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.36.tgz#1dc6f8750e89b6b979de5fe44aa993b1a2192261" + dependencies: + "@babel/code-frame" "7.0.0-beta.36" + "@babel/helper-function-name" "7.0.0-beta.36" + "@babel/types" "7.0.0-beta.36" + babylon "7.0.0-beta.36" + debug "^3.0.1" + globals "^11.1.0" + invariant "^2.2.0" + lodash "^4.2.0" + +"@babel/types@7.0.0-beta.36": + version "7.0.0-beta.36" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.36.tgz#64f2004353de42adb72f9ebb4665fc35b5499d23" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + "@gooddata/typings@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@gooddata/typings/-/typings-1.0.0.tgz#3fb9abcfbefc15745d6a0236c924d0d93e490e14" @@ -49,29 +101,29 @@ acorn@^4.0.4: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.2.tgz#911cb53e036807cf0fa778dc5d370fbd864246d7" +acorn@^5.4.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.4.1.tgz#fdc58d9d17f4a4e98d102ded826a9b9759125102" -ajv-keywords@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" +ajv-keywords@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" -ajv@^4.7.0, ajv@^4.9.1: +ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.1.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.3.tgz#c06f598778c44c6b161abafe3466b81ad1814ed2" +ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0: + version "5.5.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: co "^4.6.0" fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" - json-stable-stringify "^1.0.1" align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" @@ -85,10 +137,6 @@ amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - ansi-escapes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" @@ -105,7 +153,7 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.1.0, ansi-styles@^3.2.0: +ansi-styles@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" dependencies: @@ -136,16 +184,17 @@ are-we-there-yet@~1.1.2: readable-stream "^2.0.6" argparse@^1.0.2, argparse@^1.0.7, argparse@~1.0.2: - version "1.0.9" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" dependencies: sprintf-js "~1.0.2" -aria-query@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-0.3.0.tgz#cb8a9984e2862711c83c80ade5b8f5ca0de2b467" +aria-query@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-0.7.1.tgz#26cbb5aff64144b0a825be1846e0b16cfa00b11e" dependencies: ast-types-flow "0.0.7" + commander "^2.11.0" arr-diff@^2.0.0: version "2.0.0" @@ -169,6 +218,13 @@ array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" +array-includes@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.0.3.tgz#184b48f62d92d7452bb31b323165c7f8bd02266d" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.7.0" + array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -183,18 +239,11 @@ array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" -array.prototype.find@^2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/array.prototype.find/-/array.prototype.find-2.0.4.tgz#556a5c5362c08648323ddaeb9de9d14bc1864c90" - dependencies: - define-properties "^1.1.2" - es-abstract "^1.7.0" - arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" -asap@^2.0.0: +asap@^2.0.0, asap@~2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -257,8 +306,8 @@ async@^0.9.0, async@~0.9.0: resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" async@^2.1.4: - version "2.5.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" + version "2.6.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.0.tgz#61a29abb6fcc026fea77e56d1c6ec53a795951f4" dependencies: lodash "^4.14.0" @@ -286,6 +335,12 @@ aws4@^1.2.1, aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" +axobject-query@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-0.1.0.tgz#62f59dbc59c9f9242759ca349960e7a2fe3c36c0" + dependencies: + ast-types-flow "0.0.7" + babel-cli@6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.23.0.tgz#52ff946a2b0f64645c35e7bd5eea267aa0948c0f" @@ -307,7 +362,7 @@ babel-cli@6.23.0: optionalDependencies: chokidar "^1.6.1" -babel-code-frame@^6.16.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -315,7 +370,7 @@ babel-code-frame@^6.16.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@6.23.1, babel-core@^6.0.0, babel-core@^6.23.0: +babel-core@6.23.1: version "6.23.1" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.23.1.tgz#c143cb621bb2f621710c220c5d579d15b8a442df" dependencies: @@ -339,18 +394,44 @@ babel-core@6.23.1, babel-core@^6.0.0, babel-core@^6.23.0: slash "^1.0.0" source-map "^0.5.0" -babel-eslint@7.2.1: - version "7.2.1" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.1.tgz#079422eb73ba811e3ca0865ce87af29327f8c52f" +babel-core@^6.0.0, babel-core@^6.23.0, babel-core@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.0.tgz#af32f78b31a6fcef119c87b0fd8d9753f03a0bb8" dependencies: - babel-code-frame "^6.22.0" - babel-traverse "^6.23.1" - babel-types "^6.23.0" - babylon "^6.16.1" + babel-code-frame "^6.26.0" + babel-generator "^6.26.0" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + babel-template "^6.26.0" + babel-traverse "^6.26.0" + babel-types "^6.26.0" + babylon "^6.18.0" + convert-source-map "^1.5.0" + debug "^2.6.8" + json5 "^0.5.1" + lodash "^4.17.4" + minimatch "^3.0.4" + path-is-absolute "^1.0.1" + private "^0.1.7" + slash "^1.0.0" + source-map "^0.5.6" -babel-generator@^6.18.0, babel-generator@^6.23.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.0.tgz#ac1ae20070b79f6e3ca1d3269613053774f20dc5" +babel-eslint@8.2.1: + version "8.2.1" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.1.tgz#136888f3c109edc65376c23ebf494f36a3e03951" + dependencies: + "@babel/code-frame" "7.0.0-beta.36" + "@babel/traverse" "7.0.0-beta.36" + "@babel/types" "7.0.0-beta.36" + babylon "7.0.0-beta.36" + eslint-scope "~3.7.1" + eslint-visitor-keys "^1.0.0" + +babel-generator@^6.18.0, babel-generator@^6.23.0, babel-generator@^6.26.0: + version "6.26.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" dependencies: babel-messages "^6.23.0" babel-runtime "^6.26.0" @@ -358,7 +439,7 @@ babel-generator@^6.18.0, babel-generator@^6.23.0: detect-indent "^4.0.0" jsesc "^1.3.0" lodash "^4.17.4" - source-map "^0.5.6" + source-map "^0.5.7" trim-right "^1.0.1" babel-helper-bindify-decorators@^6.24.1: @@ -472,13 +553,20 @@ babel-helper-replace-supers@^6.24.1: babel-traverse "^6.24.1" babel-types "^6.24.1" -babel-helpers@^6.23.0: +babel-helpers@^6.23.0, babel-helpers@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" dependencies: babel-runtime "^6.22.0" babel-template "^6.24.1" +babel-jest@22.2.2: + version "22.2.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-22.2.2.tgz#eda38dca284e32cc5257f96a9b51351975de4e04" + dependencies: + babel-plugin-istanbul "^4.1.5" + babel-preset-jest "^22.2.0" + babel-jest@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-21.2.0.tgz#2ce059519a9374a2c46f2455b6fbef5ad75d863e" @@ -507,7 +595,7 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-istanbul@^4.0.0: +babel-plugin-istanbul@^4.0.0, babel-plugin-istanbul@^4.1.5: version "4.1.5" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.5.tgz#6760cdd977f411d3e175bb064f2bc327d99b2b6e" dependencies: @@ -519,6 +607,10 @@ babel-plugin-jest-hoist@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-21.2.0.tgz#2cef637259bd4b628a6cace039de5fcd14dbb006" +babel-plugin-jest-hoist@^22.2.0: + version "22.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.2.0.tgz#bd34f39d652406669713b8c89e23ef25c890b993" + babel-plugin-lodash@3.2.11: version "3.2.11" resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.2.11.tgz#21c8fdec9fe1835efaa737873e3902bdd66d5701" @@ -878,6 +970,13 @@ babel-preset-jest@^21.2.0: babel-plugin-jest-hoist "^21.2.0" babel-plugin-syntax-object-rest-spread "^6.13.0" +babel-preset-jest@^22.2.0: + version "22.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.2.0.tgz#f77b43f06ef4d8547214b2e206cc76a25c3ba0e2" + dependencies: + babel-plugin-jest-hoist "^22.2.0" + babel-plugin-syntax-object-rest-spread "^6.13.0" + babel-preset-stage-0@6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-preset-stage-0/-/babel-preset-stage-0-6.22.0.tgz#707eeb5b415da769eff9c42f4547f644f9296ef9" @@ -913,7 +1012,7 @@ babel-preset-stage-3@^6.24.1: babel-plugin-transform-exponentiation-operator "^6.24.1" babel-plugin-transform-object-rest-spread "^6.22.0" -babel-register@6.23.0, babel-register@^6.23.0: +babel-register@6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.23.0.tgz#c9aa3d4cca94b51da34826c4a0f9e08145d74ff3" dependencies: @@ -925,6 +1024,18 @@ babel-register@6.23.0, babel-register@^6.23.0: mkdirp "^0.5.1" source-map-support "^0.4.2" +babel-register@^6.23.0, babel-register@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" + dependencies: + babel-core "^6.26.0" + babel-runtime "^6.26.0" + core-js "^2.5.0" + home-or-tmp "^2.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + source-map-support "^0.4.15" + babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" @@ -965,7 +1076,11 @@ babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24 lodash "^4.17.4" to-fast-properties "^1.0.3" -babylon@^6.11.0, babylon@^6.16.1, babylon@^6.18.0: +babylon@7.0.0-beta.36: + version "7.0.0-beta.36" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.36.tgz#3a3683ba6a9a1e02b0aa507c8e63435e39305b9e" + +babylon@^6.11.0, babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -974,8 +1089,8 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" base64-js@^1.0.2: - version "1.2.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" + version "1.2.3" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801" batch@0.6.1: version "0.6.1" @@ -992,8 +1107,8 @@ big.js@^3.1.3: resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" binary-extensions@^1.0.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" + version "1.11.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" block-stream@*: version "0.0.9" @@ -1056,8 +1171,8 @@ boom@5.x.x: hoek "4.x.x" brace-expansion@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" dependencies: balanced-match "^1.0.0" concat-map "0.0.1" @@ -1156,7 +1271,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3, chalk@~1.1.1: +chalk@1.1.3, chalk@^1.1.1, chalk@^1.1.3, chalk@~1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1166,13 +1281,17 @@ chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3, chalk@~1.1.1: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796" dependencies: - ansi-styles "^3.1.0" + ansi-styles "^3.2.0" escape-string-regexp "^1.0.5" - supports-color "^4.0.0" + supports-color "^5.2.0" + +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" charenc@~0.0.1: version "0.0.2" @@ -1194,18 +1313,18 @@ chokidar@^1.0.0, chokidar@^1.6.1: fsevents "^1.0.0" ci-info@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.1.tgz#47b44df118c48d2597b56d342e7e25791060171a" + version "1.1.2" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.2.tgz#03561259db48d0474c8bdc90f5b47b068b6bbfb4" circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: - restore-cursor "^1.0.1" + restore-cursor "^2.0.0" cli-table2@0.2.0: version "0.2.0" @@ -1237,8 +1356,8 @@ cliui@^3.2.0: wrap-ansi "^2.0.0" clone@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + version "1.0.3" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.3.tgz#298d7e2231660f40c003c2ed3140decf3f53085f" co@^4.6.0: version "4.6.0" @@ -1272,8 +1391,8 @@ collections@^2.0.1: weak-map "^1.0.4" color-convert@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + version "1.9.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" dependencies: color-name "^1.1.1" @@ -1285,9 +1404,9 @@ colors@^1.1.2, colors@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" -combined-stream@^1.0.5, combined-stream@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" +combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" dependencies: delayed-stream "~1.0.0" @@ -1297,19 +1416,19 @@ combined-stream@~0.0.4: dependencies: delayed-stream "0.0.5" -commander@^2.8.1: - version "2.11.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" +commander@^2.11.0, commander@^2.8.1: + version "2.14.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa" commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" compressible@~2.0.11: - version "2.0.11" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.11.tgz#16718a75de283ed8e604041625a2064586797d8a" + version "2.0.12" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66" dependencies: - mime-db ">= 1.29.0 < 2" + mime-db ">= 1.30.0 < 2" compression@^1.5.2: version "1.7.1" @@ -1327,7 +1446,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.5.2: +concat-stream@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -1336,8 +1455,8 @@ concat-stream@^1.5.2: typedarray "^0.0.6" connect-history-api-fallback@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169" + version "1.5.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#b06873934bc5e344fef611a196a6faae0aee015a" console-browserify@^1.1.0: version "1.1.0" @@ -1362,16 +1481,16 @@ content-disposition@0.5.2: resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" content-type-parser@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.1.tgz#c3e56988c53c65127fb46d4032a3a900246fdc94" + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7" content-type@~1.0.1, content-type@~1.0.2, content-type@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" -convert-source-map@^1.1.0, convert-source-map@^1.4.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" +convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" cookie-signature@1.0.6: version "1.0.6" @@ -1381,15 +1500,19 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" +core-js@^1.0.0: + version "1.2.7" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" + core-js@^2.4.0, core-js@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b" + version "2.5.3" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -cross-spawn@^5.0.1: +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -1447,12 +1570,6 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" -d@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - dependencies: - es5-ext "^0.10.9" - damerau-levenshtein@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" @@ -1474,12 +1591,18 @@ dateformat@~1.0.12: get-stdin "^4.0.1" meow "^3.3.0" -debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.6.3, debug@^2.6.6, debug@^2.6.8: +debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" +debug@^3.0.1, debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + dependencies: + ms "2.0.0" + debug@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" @@ -1553,27 +1676,30 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" +detect-libc@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + diff@^3.2.0: version "3.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.4.0.tgz#b1d85507daf3964828de54b37d0d73ba67dda56c" -doctrine@1.5.0, doctrine@^1.2.2: +doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: esutils "^2.0.2" isarray "^1.0.0" -doctrine@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" +doctrine@^2.0.2, doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" dependencies: esutils "^2.0.2" - isarray "^1.0.0" domain-browser@^1.1.1: - version "1.1.7" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" ecc-jsbn@~0.1.1: version "0.1.1" @@ -1594,8 +1720,8 @@ emojis-list@^2.0.0: resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" encodeurl@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" encoding@^0.1.11: version "0.1.12" @@ -1616,10 +1742,10 @@ entities@~1.1.1: resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" errno@^0.1.3, errno@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" + version "0.1.7" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" dependencies: - prr "~0.0.0" + prr "~1.0.1" error-ex@^1.2.0: version "1.3.1" @@ -1628,8 +1754,8 @@ error-ex@^1.2.0: is-arrayish "^0.2.1" es-abstract@^1.7.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.9.0.tgz#690829a07cae36b222e7fd9b75c0d0573eb25227" + version "1.10.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.10.0.tgz#1ecb36c197842a00d8ee4c2dfd8646bb97d60864" dependencies: es-to-primitive "^1.1.1" function-bind "^1.1.1" @@ -1645,66 +1771,14 @@ es-to-primitive@^1.1.1: is-date-object "^1.0.1" is-symbol "^1.0.1" -es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.30" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.30.tgz#7141a16836697dbabfaaaeee41495ce29f52c939" - dependencies: - es6-iterator "2" - es6-symbol "~3.1" - es6-denodeify@^0.1.1: version "0.1.5" resolved "https://registry.yarnpkg.com/es6-denodeify/-/es6-denodeify-0.1.5.tgz#31d4d5fe9c5503e125460439310e16a2a3f39c1f" -es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-symbol "^3.1" - -es6-map@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - es6-promise@3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" -es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - dependencies: - d "1" - es5-ext "~0.10.14" - -es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" - escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -1735,150 +1809,147 @@ escodegen@^1.6.1: optionalDependencies: source-map "~0.5.6" -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-config-airbnb-base@11.1.3: - version "11.1.3" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-11.1.3.tgz#0e8db71514fa36b977fbcf977c01edcf863e0cf0" - -eslint-config-airbnb-base@^11.1.0: - version "11.3.2" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-11.3.2.tgz#8703b11abe3c88ac7ec2b745b7fdf52e00ae680a" +eslint-config-airbnb-base@12.1.0, eslint-config-airbnb-base@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz#386441e54a12ccd957b0a92564a4bafebd747944" dependencies: eslint-restricted-globals "^0.1.1" -eslint-config-airbnb@14.1.0: - version "14.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-14.1.0.tgz#355d290040bbf8e00bf8b4b19f4b70cbe7c2317f" +eslint-config-airbnb@16.1.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-16.1.0.tgz#2546bfb02cc9fe92284bf1723ccf2e87bc45ca46" dependencies: - eslint-config-airbnb-base "^11.1.0" + eslint-config-airbnb-base "^12.1.0" -eslint-config-gooddata@0.0.13: - version "0.0.13" - resolved "https://registry.yarnpkg.com/eslint-config-gooddata/-/eslint-config-gooddata-0.0.13.tgz#bbe50e3ab9f1e4a2e545a4db56539fa73c3f278c" +eslint-config-gooddata@0.0.17: + version "0.0.17" + resolved "https://registry.yarnpkg.com/eslint-config-gooddata/-/eslint-config-gooddata-0.0.17.tgz#2ea738729ed78ff3ef0ecaba6bf21fbd162bee16" dependencies: - babel-eslint "7.2.1" - eslint "3.19.0" - eslint-config-airbnb "14.1.0" - eslint-config-airbnb-base "11.1.3" - eslint-plugin-import "2.2.0" - eslint-plugin-jsx-a11y "4.0.0" - eslint-plugin-mocha "4.9.0" - eslint-plugin-react "6.10.3" + babel-eslint "8.2.1" + eslint "4.16.0" + eslint-config-airbnb "16.1.0" + eslint-config-airbnb-base "12.1.0" + eslint-plugin-import "2.8.0" + eslint-plugin-jest "21.7.0" + eslint-plugin-jsx-a11y "6.0.3" + eslint-plugin-react "7.6.1" -eslint-import-resolver-node@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" +eslint-import-resolver-node@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" dependencies: - debug "^2.2.0" - object-assign "^4.0.1" - resolve "^1.1.6" + debug "^2.6.9" + resolve "^1.5.0" -eslint-module-utils@^2.0.0: +eslint-module-utils@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" dependencies: debug "^2.6.8" pkg-dir "^1.0.0" -eslint-plugin-import@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz#72ba306fad305d67c4816348a4699a4229ac8b4e" +eslint-plugin-import@2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz#fa1b6ef31fcb3c501c09859c1b86f1fc5b986894" dependencies: builtin-modules "^1.1.1" contains-path "^0.1.0" - debug "^2.2.0" + debug "^2.6.8" doctrine "1.5.0" - eslint-import-resolver-node "^0.2.0" - eslint-module-utils "^2.0.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.1.1" has "^1.0.1" lodash.cond "^4.3.0" minimatch "^3.0.3" - pkg-up "^1.0.0" + read-pkg-up "^2.0.0" -eslint-plugin-jsx-a11y@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-4.0.0.tgz#779bb0fe7b08da564a422624911de10061e048ee" +eslint-plugin-jest@21.7.0: + version "21.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.7.0.tgz#651f1c6ce999af3ac59ab8bf8a376d742fd0fc23" + +eslint-plugin-jsx-a11y@6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.0.3.tgz#54583d1ae442483162e040e13cc31865465100e5" dependencies: - aria-query "^0.3.0" + aria-query "^0.7.0" + array-includes "^3.0.3" ast-types-flow "0.0.7" + axobject-query "^0.1.0" damerau-levenshtein "^1.0.0" emoji-regex "^6.1.0" - jsx-ast-utils "^1.0.0" - object-assign "^4.0.1" + jsx-ast-utils "^2.0.0" -eslint-plugin-mocha@4.9.0: - version "4.9.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-4.9.0.tgz#917a8b499ab8d0c01d69c6e4f81d362ee099b6fd" +eslint-plugin-react@7.6.1: + version "7.6.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.6.1.tgz#5d0e908be599f0c02fbf4eef0c7ed6f29dff7633" dependencies: - ramda "^0.23.0" - -eslint-plugin-react@6.10.3: - version "6.10.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz#c5435beb06774e12c7db2f6abaddcbf900cd3f78" - dependencies: - array.prototype.find "^2.0.1" - doctrine "^1.2.2" + doctrine "^2.0.2" has "^1.0.1" - jsx-ast-utils "^1.3.4" - object.assign "^4.0.4" + jsx-ast-utils "^2.0.1" + prop-types "^15.6.0" eslint-restricted-globals@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7" -eslint@3.19.0, eslint@^3.0.0: - version "3.19.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" +eslint-scope@^3.7.1, eslint-scope@~3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: - babel-code-frame "^6.16.0" - chalk "^1.1.3" - concat-stream "^1.5.2" - debug "^2.1.1" - doctrine "^2.0.0" - escope "^3.6.0" - espree "^3.4.0" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +eslint@4.16.0: + version "4.16.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.16.0.tgz#934ada9e98715e1d7bbfd6f6f0519ed2fab35cc1" + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.2" esquery "^1.0.0" - estraverse "^4.2.0" esutils "^2.0.2" file-entry-cache "^2.0.0" - glob "^7.0.3" - globals "^9.14.0" - ignore "^3.2.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" imurmurhash "^0.1.4" - inquirer "^0.12.0" - is-my-json-valid "^2.10.0" + inquirer "^3.0.6" is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" natural-compare "^1.4.0" optionator "^0.8.2" - path-is-inside "^1.0.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.7.5" - strip-bom "^3.0.0" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" strip-json-comments "~2.0.1" - table "^3.7.8" + table "^4.0.1" text-table "~0.2.0" - user-home "^2.0.0" -espree@^3.4.0: - version "3.5.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.1.tgz#0c988b8ab46db53100a1954ae4ba995ddd27d87e" +espree@^3.5.2: + version "3.5.3" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.3.tgz#931e0af64e7fbbed26b050a29daad1fc64799fa6" dependencies: - acorn "^5.1.1" + acorn "^5.4.0" acorn-jsx "^3.0.0" esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: @@ -1926,13 +1997,6 @@ etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - dependencies: - d "1" - es5-ext "~0.10.14" - eventemitter2@~0.4.13: version "0.4.14" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-0.4.14.tgz#8f61b75cde012b2e9eb284d4545583b5643b61ab" @@ -1969,10 +2033,6 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - exit@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -2045,8 +2105,8 @@ express@4.14.1: vary "~1.1.0" express@^4.13.1, express@^4.13.3: - version "4.16.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.16.1.tgz#6b33b560183c9b253b7b62144df33a4654ac9ed0" + version "4.16.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.16.2.tgz#e35c6dfe2d64b7dca0a5cd4f21781be3299e076c" dependencies: accepts "~1.3.4" array-flatten "1.1.1" @@ -2083,20 +2143,36 @@ extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" +external-editor@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" dependencies: is-extglob "^1.0.0" -extsprintf@1.3.0, extsprintf@^1.2.0: +extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" +fast-json-stable-stringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" + fast-levenshtein@2.0.6, fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" @@ -2119,6 +2195,18 @@ fb-watchman@^2.0.0: dependencies: bser "^2.0.0" +fbjs@^0.8.16: + version "0.8.16" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" + dependencies: + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" + loose-envify "^1.0.0" + object-assign "^4.1.0" + promise "^7.1.1" + setimmediate "^1.0.5" + ua-parser-js "^0.7.9" + fetch-cookie@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.4.0.tgz#8f78b830b380bac72df1c138d8ffeb01f3ee3b23" @@ -2134,12 +2222,11 @@ fetch-mock@5.12.2: node-fetch "^1.3.3" path-to-regexp "^1.7.0" -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" dependencies: escape-string-regexp "^1.0.5" - object-assign "^4.1.0" file-entry-cache@^2.0.0: version "2.0.0" @@ -2270,11 +2357,11 @@ form-data@~2.1.1: mime-types "^2.1.12" form-data@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.1.tgz#6fb94fbd71885306d73d15cc497fe4cc4ecd44bf" + version "2.3.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" dependencies: asynckit "^0.4.0" - combined-stream "^1.0.5" + combined-stream "1.0.6" mime-types "^2.1.12" forwarded@~0.1.0, forwarded@~0.1.2: @@ -2300,19 +2387,19 @@ fs-extra@^0.30.0: rimraf "^2.2.8" fs-readdir-recursive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.0.0.tgz#8cd1745c8b4f8a29c8caec392476921ba195f560" + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fsevents@^1.0.0, fsevents@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" + version "1.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" dependencies: nan "^2.3.0" - node-pre-gyp "^0.6.36" + node-pre-gyp "^0.6.39" fstream-ignore@^1.0.5: version "1.0.5" @@ -2331,10 +2418,14 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" -function-bind@^1.0.2, function-bind@^1.1.0, function-bind@^1.1.1: +function-bind@^1.0.2, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -2354,16 +2445,6 @@ gaze@^1.0.0: dependencies: globule "^1.0.0" -generate-function@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" - -generate-object-property@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" - dependencies: - is-property "^1.0.0" - get-caller-file@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" @@ -2435,7 +2516,11 @@ glob@~7.0.0: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^9.14.0, globals@^9.18.0: +globals@^11.0.1, globals@^11.1.0: + version "11.3.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.3.0.tgz#e04fdb7b9796d8adac9c8f64c14837b2313378b0" + +globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -2590,15 +2675,9 @@ grunt@1.0.1: path-is-absolute "~1.0.0" rimraf "~2.2.8" -gruntify-eslint@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/gruntify-eslint/-/gruntify-eslint-3.1.0.tgz#2c777fb388637fe447f8c56cd253caef6c8795e7" - dependencies: - eslint "^3.0.0" - handlebars@^4.0.1, handlebars@^4.0.3: - version "4.0.10" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" + version "4.0.11" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.11.tgz#630a35dfe0294bc281edae6ffc5d329fc7982dcc" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -2638,9 +2717,9 @@ has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" -has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" has-unicode@^2.0.0: version "2.0.1" @@ -2688,8 +2767,8 @@ hoek@2.x.x: resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" hoek@4.x.x: - version "4.2.0" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.0.tgz#72d9d0754f7fe25ca2d01ad8f8f9a9449a89526d" + version "4.2.1" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.2.1.tgz#9634502aa12c445dd5a7c5734b572bb8738aacbb" home-or-tmp@^2.0.0: version "2.0.0" @@ -2707,8 +2786,8 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" html-encoding-sniffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.1.tgz#79bf7a785ea495fe66165e734153f363ff5437da" + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" dependencies: whatwg-encoding "^1.0.1" @@ -2744,8 +2823,8 @@ http-errors@~1.5.1: statuses ">= 1.3.1 < 2" http-parser-js@>=0.4.0: - version "0.4.9" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.9.tgz#ea1a04fb64adff0242e9974f297dd4c3cad271e1" + version "0.4.10" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" http-proxy-middleware@~0.17.1: version "0.17.4" @@ -2795,7 +2874,7 @@ iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" -iconv-lite@0.4.19, iconv-lite@~0.4.13: +iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -2803,9 +2882,9 @@ ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" -ignore@^3.2.0: - version "3.3.5" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.5.tgz#c4e715455f6073a8d7e5dae72d2fc9d71663dba6" +ignore@^3.3.3: + version "3.3.7" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" imports-loader@0.7.0: version "0.7.0" @@ -2844,36 +2923,33 @@ inherits@2.0.1: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" ini@~1.3.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" -inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" cli-width "^2.0.0" - figures "^1.3.5" + external-editor "^2.0.4" + figures "^2.0.0" lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" through "^2.3.6" interpret@^0.6.4: version "0.6.6" resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" -interpret@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.4.tgz#820cdd588b868ffb191a809506d6c9c8f212b1b0" - -invariant@2.2.2, invariant@^2.2.2: +invariant@2.2.2, invariant@^2.2.0, invariant@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" dependencies: @@ -2902,8 +2978,8 @@ is-binary-path@^1.0.0: binary-extensions "^1.0.0" is-buffer@^1.1.5, is-buffer@~1.1.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" is-builtin-module@^1.0.0: version "1.0.0" @@ -2916,8 +2992,8 @@ is-callable@^1.1.1, is-callable@^1.1.3: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" is-ci@^1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.0.10.tgz#f739336b2632365061a9d48270cd56ae3369318e" + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.1.0.tgz#247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5" dependencies: ci-info "^1.0.0" @@ -2975,15 +3051,6 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-my-json-valid@^2.10.0: - version "2.16.1" - resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz#5a846777e2c2620d1e69104e5d3a03b1f6088f11" - dependencies: - generate-function "^2.0.0" - generate-object-property "^1.1.0" - jsonpointer "^4.0.0" - xtend "^4.0.0" - is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" @@ -3007,8 +3074,8 @@ is-path-in-cwd@^1.0.0: is-path-inside "^1.0.0" is-path-inside@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" dependencies: path-is-inside "^1.0.1" @@ -3020,9 +3087,9 @@ is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" -is-property@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" is-regex@^1.0.4: version "1.0.4" @@ -3031,10 +3098,8 @@ is-regex@^1.0.4: has "^1.0.1" is-resolvable@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" - dependencies: - tryit "^1.0.1" + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" is-stream@^1.0.1, is-stream@^1.1.0: version "1.1.0" @@ -3070,7 +3135,7 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" -isomorphic-fetch@2.2.1: +isomorphic-fetch@2.2.1, isomorphic-fetch@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" dependencies: @@ -3082,17 +3147,17 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" istanbul-api@^1.1.1: - version "1.1.14" - resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.14.tgz#25bc5701f7c680c0ffff913de46e3619a3a6e680" + version "1.2.2" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.2.2.tgz#e17cd519dd5ec4141197f246fdf380b75487f3b1" dependencies: async "^2.1.4" fileset "^2.0.2" - istanbul-lib-coverage "^1.1.1" - istanbul-lib-hook "^1.0.7" - istanbul-lib-instrument "^1.8.0" - istanbul-lib-report "^1.1.1" - istanbul-lib-source-maps "^1.2.1" - istanbul-reports "^1.1.2" + istanbul-lib-coverage "^1.1.2" + istanbul-lib-hook "^1.1.0" + istanbul-lib-instrument "^1.9.2" + istanbul-lib-report "^1.1.3" + istanbul-lib-source-maps "^1.2.3" + istanbul-reports "^1.1.4" js-yaml "^3.7.0" mkdirp "^0.5.1" once "^1.4.0" @@ -3105,50 +3170,50 @@ istanbul-instrumenter-loader@0.2.0: loader-utils "0.x.x" object-assign "4.x.x" -istanbul-lib-coverage@^1.0.1, istanbul-lib-coverage@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz#73bfb998885299415c93d38a3e9adf784a77a9da" +istanbul-lib-coverage@^1.0.1, istanbul-lib-coverage@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.2.tgz#4113c8ff6b7a40a1ef7350b01016331f63afde14" -istanbul-lib-hook@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz#dd6607f03076578fe7d6f2a630cf143b49bacddc" +istanbul-lib-hook@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz#8538d970372cb3716d53e55523dd54b557a8d89b" dependencies: append-transform "^0.4.0" -istanbul-lib-instrument@^1.4.2, istanbul-lib-instrument@^1.7.5, istanbul-lib-instrument@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.8.0.tgz#66f6c9421cc9ec4704f76f2db084ba9078a2b532" +istanbul-lib-instrument@^1.4.2, istanbul-lib-instrument@^1.7.5, istanbul-lib-instrument@^1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.2.tgz#84905bf47f7e0b401d6b840da7bad67086b4aab6" dependencies: babel-generator "^6.18.0" babel-template "^6.16.0" babel-traverse "^6.18.0" babel-types "^6.18.0" babylon "^6.18.0" - istanbul-lib-coverage "^1.1.1" + istanbul-lib-coverage "^1.1.2" semver "^5.3.0" -istanbul-lib-report@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#f0e55f56655ffa34222080b7a0cd4760e1405fc9" +istanbul-lib-report@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.3.tgz#2df12188c0fa77990c0d2176d2d0ba3394188259" dependencies: - istanbul-lib-coverage "^1.1.1" + istanbul-lib-coverage "^1.1.2" mkdirp "^0.5.1" path-parse "^1.0.5" supports-color "^3.1.2" -istanbul-lib-source-maps@^1.1.0, istanbul-lib-source-maps@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz#a6fe1acba8ce08eebc638e572e294d267008aa0c" +istanbul-lib-source-maps@^1.1.0, istanbul-lib-source-maps@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.3.tgz#20fb54b14e14b3fb6edb6aca3571fd2143db44e6" dependencies: - debug "^2.6.3" - istanbul-lib-coverage "^1.1.1" + debug "^3.1.0" + istanbul-lib-coverage "^1.1.2" mkdirp "^0.5.1" rimraf "^2.6.1" source-map "^0.5.3" -istanbul-reports@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.2.tgz#0fb2e3f6aa9922bd3ce45d05d8ab4d5e8e07bd4f" +istanbul-reports@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.4.tgz#5ccba5e22b7b5a5d91d5e0a830f89be334bf97bd" dependencies: handlebars "^4.0.3" @@ -3412,7 +3477,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@3.x, js-yaml@^3.5.1, js-yaml@^3.7.0: +js-yaml@3.x, js-yaml@^3.7.0, js-yaml@^3.9.1: version "3.10.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" dependencies: @@ -3474,7 +3539,11 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" -json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + +json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: @@ -3488,7 +3557,7 @@ json3@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" -json5@^0.5.0: +json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -3502,10 +3571,6 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" -jsonpointer@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" - jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -3515,9 +3580,11 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.3.4: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" +jsx-ast-utils@^2.0.0, jsx-ast-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" + dependencies: + array-includes "^3.0.3" kind-of@^3.0.2: version "3.2.2" @@ -3565,8 +3632,8 @@ linkify-it@~1.2.0: uc.micro "^1.0.1" livereload-js@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.2.2.tgz#6c87257e648ab475bc24ea257457edcc1f8d0bc2" + version "2.3.0" + resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.3.0.tgz#c3ab22e8aaf5bf3505d80d098cbad67726548c9a" load-json-file@^1.0.0: version "1.1.0" @@ -3617,7 +3684,7 @@ lodash.defaults@4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" -lodash@4.17.4, lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.8.0, lodash@~4.17.4: +lodash@4.17.4: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -3625,6 +3692,10 @@ lodash@^3.10.1, lodash@~3.10.1: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" +lodash@^4.0.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.8.0, lodash@~4.17.4: + version "4.17.5" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" + lodash@~4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.3.0.tgz#efd9c4a6ec53f3b05412429915c3e4824e4d25a4" @@ -3633,7 +3704,7 @@ longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" -loose-envify@^1.0.0: +loose-envify@^1.0.0, loose-envify@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" dependencies: @@ -3762,7 +3833,11 @@ micromatch@^2.1.5, micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" -"mime-db@>= 1.29.0 < 2", mime-db@~1.30.0: +"mime-db@>= 1.30.0 < 2": + version "1.33.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" + +mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" @@ -3780,10 +3855,14 @@ mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" -mime@1.4.1, mime@^1.2.11, mime@^1.3.4: +mime@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" +mime@^1.2.11, mime@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + mime@~1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" @@ -3793,8 +3872,8 @@ mimeparse@^0.1.4: resolved "https://registry.yarnpkg.com/mimeparse/-/mimeparse-0.1.4.tgz#dafb02752370fd226093ae3152c271af01ac254a" mimic-fn@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" mini-map@^1.0.0: version "1.0.0" @@ -3818,7 +3897,7 @@ minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" -mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: +mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -3836,13 +3915,13 @@ ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" nan@^2.3.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" + version "2.8.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" natural-compare@^1.4.0: version "1.4.0" @@ -3892,18 +3971,19 @@ node-libs-browser@^0.6.0: vm-browserify "0.0.4" node-notifier@^5.0.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" + version "5.2.1" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.2.1.tgz#fa313dd08f5517db0e2502e5758d664ac69f9dea" dependencies: growly "^1.3.0" - semver "^5.3.0" - shellwords "^0.1.0" - which "^1.2.12" + semver "^5.4.1" + shellwords "^0.1.1" + which "^1.3.0" -node-pre-gyp@^0.6.36: - version "0.6.38" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.38.tgz#e92a20f83416415bb4086f6d1fb78b3da73d113d" +node-pre-gyp@^0.6.39: + version "0.6.39" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" dependencies: + detect-libc "^1.0.2" hawk "3.1.3" mkdirp "^0.5.1" nopt "^4.0.1" @@ -3967,8 +4047,8 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" "nwmatcher@>= 1.3.9 < 2.0.0": - version "1.4.2" - resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.2.tgz#c5e545ab40d22a56b0326531c4beaed7a888b3ea" + version "1.4.3" + resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.3.tgz#64348e3b3d80f035b40ac11563d278f8b72db89c" oauth-sign@~0.3.0: version "0.3.0" @@ -3978,22 +4058,14 @@ oauth-sign@~0.8.1, oauth-sign@~0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@4.x.x, object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@4.x.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" -object-keys@^1.0.10, object-keys@^1.0.8: +object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" -object.assign@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc" - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.0" - object-keys "^1.0.10" - object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -4017,9 +4089,11 @@ once@1.x, once@^1.3.0, once@^1.3.3, once@^1.4.0: dependencies: wrappy "1" -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" open@0.0.5: version "0.0.5" @@ -4065,13 +4139,13 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" osenv@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" dependencies: os-homedir "^1.0.0" os-tmpdir "^1.0.0" @@ -4093,8 +4167,10 @@ p-finally@^1.0.0: resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" p-limit@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + version "1.2.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.2.0.tgz#0e92b6bedcb59f022c13d0f1949dc82d15909f1c" + dependencies: + p-try "^1.0.0" p-locate@^2.0.0: version "2.0.0" @@ -4102,6 +4178,10 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + pako@~0.2.0: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" @@ -4143,11 +4223,11 @@ path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" -path-is-absolute@^1.0.0, path-is-absolute@~1.0.0: +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1, path-is-absolute@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1: +path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -4219,15 +4299,9 @@ pkg-dir@^1.0.0: dependencies: find-up "^1.0.0" -pkg-up@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" - dependencies: - find-up "^1.0.0" - -pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" pop-arrayify@^1.0.0: version "1.0.0" @@ -4301,9 +4375,9 @@ pretty-format@^21.2.1: ansi-regex "^3.0.0" ansi-styles "^3.2.0" -private@^0.1.6: - version "0.1.7" - resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" +private@^0.1.6, private@^0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" process-nextick-args@~2.0.0: version "2.0.0" @@ -4313,9 +4387,23 @@ process@^0.11.0, process@~0.11.0: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -progress@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" + +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + dependencies: + asap "~2.0.3" + +prop-types@^15.6.0: + version "15.6.0" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.3.1" + object-assign "^4.1.1" proxy-addr@~1.1.3: version "1.1.5" @@ -4331,9 +4419,9 @@ proxy-addr@~2.0.2: forwarded "~0.1.2" ipaddr.js "1.5.2" -prr@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" +prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" pseudomap@^1.0.2: version "1.0.2" @@ -4414,10 +4502,6 @@ querystringify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" -ramda@^0.23.0: - version "0.23.0" - resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.23.0.tgz#ccd13fff73497a93974e3e86327bfd87bd6e8e2b" - randomatic@^1.1.3: version "1.1.7" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" @@ -4447,8 +4531,8 @@ raw-body@~2.1.5: unpipe "1.0.0" rc@^1.1.7: - version "1.2.1" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" + version "1.2.5" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.5.tgz#275cd687f6e3b36cc756baa26dfee80a790301fd" dependencies: deep-extend "~0.4.0" ini "~1.3.0" @@ -4515,20 +4599,6 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - dependencies: - resolve "^1.1.6" - redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" @@ -4545,8 +4615,8 @@ regenerator-runtime@^0.10.5: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" regenerator-runtime@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz#7e54fe5b5ccd5d6624ea6255c3473be090b802e1" + version "0.11.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" regenerator-transform@^0.10.0: version "0.10.1" @@ -4683,14 +4753,14 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" -require-uncached@^1.0.2: +require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: caller-path "^0.1.0" resolve-from "^1.0.0" -requires-port@1.0.x, requires-port@1.x.x: +requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -4702,18 +4772,18 @@ resolve@1.1.7, resolve@1.1.x, resolve@~1.1.0: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" -resolve@^1.1.6: - version "1.4.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86" +resolve@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" + onetime "^2.0.0" + signal-exit "^3.0.2" right-align@^0.1.1: version "0.1.3" @@ -4735,23 +4805,29 @@ ripemd160@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: - once "^1.3.0" + is-promise "^2.1.0" -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" sane@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-2.2.0.tgz#d6d2e2fcab00e3d283c93b912b7c3a20846f1d56" + version "2.4.1" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.4.1.tgz#29f991208cf28636720efdc584293e7fd66663a5" dependencies: anymatch "^1.3.0" exec-sh "^0.2.0" @@ -4771,9 +4847,9 @@ sax@^1.2.1: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" -"semver@2 || 3 || 4 || 5", semver@^5.3.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1: + version "5.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" send@0.14.2: version "0.14.2" @@ -4849,6 +4925,10 @@ set-immediate-shim@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + setprototypeof@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" @@ -4875,15 +4955,7 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" -shelljs@^0.7.5: - version "0.7.8" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -shellwords@^0.1.0: +shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" @@ -4895,9 +4967,11 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" sntp@0.2.x: version "0.2.4" @@ -4912,8 +4986,8 @@ sntp@1.x.x: hoek "2.x.x" sntp@2.x.x: - version "2.0.2" - resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.0.2.tgz#5064110f0af85f7cfdb7d6b67a40028ce52b4b2b" + version "2.1.0" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-2.1.0.tgz#2c6cec14fedc2222739caf9b5c3d85d1cc5a2cc8" dependencies: hoek "4.x.x" @@ -4929,17 +5003,17 @@ sockjs-client@^1.0.3: url-parse "^1.1.8" sockjs@^0.3.15: - version "0.3.18" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.18.tgz#d9b289316ca7df77595ef299e075f0f937eb4207" + version "0.3.19" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d" dependencies: faye-websocket "^0.10.0" - uuid "^2.0.2" + uuid "^3.0.1" source-list-map@~0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" -source-map-support@^0.4.2: +source-map-support@^0.4.15, source-map-support@^0.4.2: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" dependencies: @@ -4957,7 +5031,7 @@ source-map@^0.4.4, source-map@~0.4.1: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.6: +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.1, source-map@~0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -4999,7 +5073,11 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -statuses@1, "statuses@>= 1.3.1 < 2", statuses@~1.3.1: +statuses@1, "statuses@>= 1.3.1 < 2": + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + +statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" @@ -5029,7 +5107,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0: +string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -5096,34 +5174,34 @@ supports-color@^3.1.0, supports-color@^3.1.1, supports-color@^3.1.2: dependencies: has-flag "^1.0.0" -supports-color@^4.0.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e" +supports-color@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a" dependencies: - has-flag "^2.0.0" + has-flag "^3.0.0" symbol-tree@^3.2.1: version "3.2.2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" -table@^3.7.8: - version "3.8.3" - resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" +table@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" dependencies: - ajv "^4.7.0" - ajv-keywords "^1.0.0" - chalk "^1.1.1" - lodash "^4.0.0" - slice-ansi "0.0.4" - string-width "^2.0.0" + ajv "^5.2.3" + ajv-keywords "^2.1.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" tapable@^0.1.8, tapable@~0.1.8: version "0.1.10" resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" tar-pack@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" + version "3.4.1" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" dependencies: debug "^2.2.0" fstream "^1.0.10" @@ -5143,8 +5221,8 @@ tar@^2.2.1: inherits "2" test-exclude@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.1.1.tgz#4d84964b0966b0087ecc334a2ce002d3d9341e26" + version "4.2.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.0.tgz#07e3613609a362c74516a717515e13322ab45b3c" dependencies: arrify "^1.0.1" micromatch "^2.3.11" @@ -5185,6 +5263,12 @@ tiny-lr@^0.2.1: parseurl "~1.3.0" qs "~5.1.0" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -5193,6 +5277,10 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + tough-cookie@>=0.12.0, tough-cookie@^2.3.1, tough-cookie@^2.3.2, tough-cookie@~2.3.0, tough-cookie@~2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.3.tgz#0b618a5565b6dea90bf3425d04d55edc475a7561" @@ -5211,10 +5299,6 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -tryit@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" - tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" @@ -5250,9 +5334,17 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +typescript@2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.7.2.tgz#2d615a1ef4aee4f574425cdff7026edf81919836" + +ua-parser-js@^0.7.9: + version "0.7.17" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" + uc.micro@^1.0.0, uc.micro@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" + version "1.0.5" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.5.tgz#0c65f15f815aa08b560a61ce8b4db7ffc3f45376" uglify-js@^2.6: version "2.8.29" @@ -5296,11 +5388,11 @@ url-parse@1.0.x: requires-port "1.0.x" url-parse@^1.1.8: - version "1.1.9" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.9.tgz#c67f1d775d51f0a18911dd7b3ffad27bb9e5bd19" + version "1.2.0" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.2.0.tgz#3a19e8aaa6d023ddd27dcc44cb4fc8f7fec23986" dependencies: querystringify "~1.0.0" - requires-port "1.0.x" + requires-port "~1.0.0" url-safe@^2.0.0: version "2.0.0" @@ -5329,12 +5421,6 @@ user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" -user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - dependencies: - os-homedir "^1.0.0" - util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -5353,13 +5439,9 @@ utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" -uuid@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" - -uuid@^3.0.0, uuid@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" +uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" v8flags@^2.0.10: version "2.1.1" @@ -5433,11 +5515,11 @@ webpack-core@~0.6.0: source-map "~0.4.1" webpack-dev-middleware@^1.4.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz#d34efefb2edda7e1d3b5dbe07289513219651709" + version "1.12.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz#f8fc1120ce3b4fc5680ceecb43d777966b21105e" dependencies: memory-fs "~0.4.1" - mime "^1.3.4" + mime "^1.5.0" path-is-absolute "^1.0.0" range-parser "^1.0.3" time-stamp "^2.0.0" @@ -5488,14 +5570,14 @@ websocket-driver@>=0.5.1: websocket-extensions ">=0.1.1" websocket-extensions@>=0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.2.tgz#0e18781de629a18308ce1481650f67ffa2693a5d" + version "0.1.3" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" whatwg-encoding@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.1.tgz#3c6c451a198ee7aec55b1ec61d0920c67801a5f4" + version "1.0.3" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" dependencies: - iconv-lite "0.4.13" + iconv-lite "0.4.19" whatwg-fetch@>=0.10.0: version "2.0.3" @@ -5512,7 +5594,7 @@ which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" -which@^1.1.1, which@^1.2.12, which@^1.2.9: +which@^1.1.1, which@^1.2.12, which@^1.2.9, which@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" dependencies: @@ -5547,8 +5629,8 @@ wordwrap@~0.0.2: resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" worker-farm@^1.3.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.0.tgz#adfdf0cd40581465ed0a1f648f9735722afd5c8d" + version "1.5.2" + resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.5.2.tgz#32b312e5dc3d5d45d79ef44acc2587491cd729ae" dependencies: errno "^0.1.4" xtend "^4.0.1" @@ -5586,7 +5668,7 @@ xml@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" -xtend@^4.0.0, xtend@^4.0.1: +xtend@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"