From 4936b0a5f2d4c3f2ff60b3f65f1446fc881c0641 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Wed, 14 Mar 2018 18:10:26 +0100 Subject: [PATCH 1/8] Add pubsub interface definition --- lerna.json | 2 +- package.json | 2 +- packages/api-format/package.json | 8 +- packages/api-format/src/input.js | 7 +- packages/api-format/src/input.spec.js | 2 +- packages/api-format/src/output.spec.js | 16 +- packages/api-format/src/util.js | 4 +- packages/api-format/src/util.spec.js | 4 +- packages/api-jsonrpc/package.json | 2 +- packages/api-jsonrpc/src/types.js | 8 +- packages/api-provider/package.json | 4 +- packages/api-provider/src/types.js | 8 + packages/api-provider/src/ws/index.js | 29 +- packages/api-provider/src/ws/index.spec.js | 26 +- packages/api/package.json | 10 +- packages/api/src/api.js | 25 - packages/api/src/api.spec.js | 39 - packages/api/src/create/interface.js | 49 +- packages/api/src/create/interface.spec.js | 40 +- packages/api/src/create/method.js | 28 + packages/api/src/create/method.spec.js | 55 + packages/api/src/create/params.js | 15 + packages/api/src/create/subscribe.js | 40 + packages/api/src/create/subscribe.spec.js | 70 + packages/api/src/index.js | 18 +- packages/api/src/index.spec.js | 36 +- packages/api/src/types.js | 6 +- yarn.lock | 1603 +++++++++++++++----- 28 files changed, 1601 insertions(+), 555 deletions(-) delete mode 100644 packages/api/src/api.js delete mode 100644 packages/api/src/api.spec.js create mode 100644 packages/api/src/create/method.js create mode 100644 packages/api/src/create/method.spec.js create mode 100644 packages/api/src/create/params.js create mode 100644 packages/api/src/create/subscribe.js create mode 100644 packages/api/src/create/subscribe.spec.js diff --git a/lerna.json b/lerna.json index ee1954358b0d..e72f6df4ee7e 100644 --- a/lerna.json +++ b/lerna.json @@ -10,5 +10,5 @@ "packages": [ "packages/*" ], - "version": "0.7.1" + "version": "0.8.0" } diff --git a/package.json b/package.json index 3ae334b305b5..2342a9e79679 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "test": "jest --coverage" }, "devDependencies": { - "@polkadot/dev": "^0.15.1", + "@polkadot/dev": "^0.16.17", "lerna": "^2.5.1" } } diff --git a/packages/api-format/package.json b/packages/api-format/package.json index cb3630b1457b..25886213e99a 100644 --- a/packages/api-format/package.json +++ b/packages/api-format/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/api-format", - "version": "0.7.1", + "version": "0.8.0", "description": "Input/Output formatters for JsonRPC exchange", "main": "index.js", "keywords": [ @@ -30,11 +30,11 @@ "test": "echo \"Tests only available from root wrapper\"" }, "devDependencies": { - "@polkadot/api-jsonrpc": "^0.7.1" + "@polkadot/api-jsonrpc": "^0.8.0" }, "dependencies": { - "@polkadot/primitives-json": "^0.4.10", - "@polkadot/util": "^0.13.1", + "@polkadot/primitives-json": "^0.9.4", + "@polkadot/util": "^0.17.2", "babel-runtime": "^6.26.0" } } diff --git a/packages/api-format/src/input.js b/packages/api-format/src/input.js index 5414ed7b6f52..3c431263ae63 100644 --- a/packages/api-format/src/input.js +++ b/packages/api-format/src/input.js @@ -4,11 +4,10 @@ // @flow import type { InterfaceInputType } from '@polkadot/api-jsonrpc/types'; +import type { Hash } from '@polkadot/primitives/base'; const accountIdEncode = require('@polkadot/primitives-json/accountId/encode'); -const h256Encode = require('@polkadot/primitives-json/h256/encode'); const hashEncode = require('@polkadot/primitives-json/hash/encode'); -const headerHashEncode = require('@polkadot/primitives-json/headerHash/encode'); const echo = require('./echo'); const util = require('./util'); @@ -16,8 +15,8 @@ const util = require('./util'); const formatters = { 'Address': accountIdEncode, 'CallData': hashEncode, - 'H256': h256Encode, - 'HeaderHash': headerHashEncode, + 'H256': (value: Hash) => hashEncode(value, 256), + 'HeaderHash': hashEncode, 'String': echo }; diff --git a/packages/api-format/src/input.spec.js b/packages/api-format/src/input.spec.js index bb014b1809d9..1c4155eb8e90 100644 --- a/packages/api-format/src/input.spec.js +++ b/packages/api-format/src/input.spec.js @@ -12,7 +12,7 @@ describe('formatInputs', () => { { name: 'foo', type: 'Address' }, { name: 'bar', type: 'H256' } ], - ['0x1234', '0xabcd'] + [new Uint8Array([0x12, 0x34]), new Uint8Array([0xab, 0xcd])] ) ).toEqual([ '0x1234', diff --git a/packages/api-format/src/output.spec.js b/packages/api-format/src/output.spec.js index 4b088fc39182..8121e5e044d5 100644 --- a/packages/api-format/src/output.spec.js +++ b/packages/api-format/src/output.spec.js @@ -16,24 +16,22 @@ describe('formatOutput', () => { stateRoot: '0x5678', transactionRoot: '0xabcd', digest: { - parachainActivityBitfield: '0x1234', logs: ['0x5678', '0x789a'] } }) ) ).toEqual( JSON.stringify({ - parentHash: '0x1234', - number: new BN(0x1234), - stateRoot: '0x5678', - transactionRoot: '0xabcd', digest: { - parachainActivityBitfield: Buffer.from([0x12, 0x34]), logs: [ - Buffer.from([0x56, 0x78]), - Buffer.from([0x78, 0x9a]) + new Uint8Array([0x56, 0x78]), + new Uint8Array([0x78, 0x9a]) ] - } + }, + number: new BN(0x1234), + parentHash: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x12, 0x34]), + stateRoot: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x56, 0x78]), + transactionRoot: new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xab, 0xcd]) }) ); }); diff --git a/packages/api-format/src/util.js b/packages/api-format/src/util.js index 2776d34cca90..9ab8e64e5bc1 100644 --- a/packages/api-format/src/util.js +++ b/packages/api-format/src/util.js @@ -12,6 +12,8 @@ type FormattersFunctionMap = { }; const isUndefined = require('@polkadot/util/is/undefined'); +const l = require('@polkadot/util/logger')('api-format'); + const echo = require('./echo'); const arrayTypeRegex = /\[\]$/; @@ -20,7 +22,7 @@ function formatSingleType (formatters: FormattersFunctionMap, type: FormattersFu const formatter: FormatterFunction = formatters[type]; if (isUndefined(formatter)) { - console.warn(`Unable to find default formatter for '${type}', falling back to echo`); + l.warn(`Unable to find default formatter for '${type}', falling back to echo`); return echo(value); } diff --git a/packages/api-format/src/util.spec.js b/packages/api-format/src/util.spec.js index c6b24edd3b1a..4abbfe89402b 100644 --- a/packages/api-format/src/util.spec.js +++ b/packages/api-format/src/util.spec.js @@ -37,7 +37,9 @@ describe('util', () => { it('logs a warning with unknown types', () => { format(formatters, 'Unknown', 'test'); - expect(warnSpy).toHaveBeenCalledWith("Unable to find default formatter for 'Unknown', falling back to echo"); + expect(warnSpy).toHaveBeenCalledWith( + expect.anything(), expect.anything(), "Unable to find default formatter for 'Unknown', falling back to echo" + ); }); it('wraps exceptions with the type', () => { diff --git a/packages/api-jsonrpc/package.json b/packages/api-jsonrpc/package.json index a1e7257acb7d..270dc748dd34 100644 --- a/packages/api-jsonrpc/package.json +++ b/packages/api-jsonrpc/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/api-jsonrpc", - "version": "0.7.1", + "version": "0.8.0", "description": "Method definitions for the Polkadot RPC layer", "main": "index.js", "engines": { diff --git a/packages/api-jsonrpc/src/types.js b/packages/api-jsonrpc/src/types.js index c56f41f74071..7086979ce354 100644 --- a/packages/api-jsonrpc/src/types.js +++ b/packages/api-jsonrpc/src/types.js @@ -24,10 +24,12 @@ export type InterfaceMethodDefinition = { export type InterfaceTypes = 'chain' | 'state'; +export type InterfaceDefinition$Methods = { + [string]: InterfaceMethodDefinition +}; + export type InterfaceDefinition = { - methods: { - [string]: InterfaceMethodDefinition - } + methods: InterfaceDefinition$Methods }; export type InterfaceDefinitions = { diff --git a/packages/api-provider/package.json b/packages/api-provider/package.json index 63d717bb2e8a..62609379473d 100644 --- a/packages/api-provider/package.json +++ b/packages/api-provider/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/api-provider", - "version": "0.7.1", + "version": "0.8.0", "description": "Transport providers for the API", "main": "index.js", "keywords": [ @@ -34,7 +34,7 @@ "nock": "^9.1.0" }, "dependencies": { - "@polkadot/util": "^0.13.1", + "@polkadot/util": "^0.17.2", "babel-runtime": "^6.26.0", "isomorphic-fetch": "^2.2.1", "websocket": "^1.0.25" diff --git a/packages/api-provider/src/types.js b/packages/api-provider/src/types.js index 13b7f850379c..44895eca60f8 100644 --- a/packages/api-provider/src/types.js +++ b/packages/api-provider/src/types.js @@ -25,5 +25,13 @@ export type JsonRpcResponse = JsonRpcObject & JsonRpcResponseBase; export interface ProviderInterface { +isConnected: boolean; + send (method: string, params: Array): Promise; } + +export type ProviderInterface$Subscribe$Callback = (error: ?Error, result: mixed) => void; + +export interface ProviderInterface$Subscribe extends ProviderInterface { + subscribe (method: string, params: Array, cb: ProviderInterface$Subscribe$Callback): Promise; + unsubscribe (id: number): Promise; +} diff --git a/packages/api-provider/src/ws/index.js b/packages/api-provider/src/ws/index.js index 086b36c045f9..6f8e3a63ec50 100644 --- a/packages/api-provider/src/ws/index.js +++ b/packages/api-provider/src/ws/index.js @@ -3,21 +3,22 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { JsonRpcResponse, ProviderInterface } from '../types'; +import type { JsonRpcResponse, ProviderInterface$Subscribe, ProviderInterface$Subscribe$Callback } from '../types'; -type AwaitingType = { +type Awaiting = { callback: (error: ?Error, result: mixed) => void }; require('./polyfill'); +const l = require('@polkadot/util/logger')('ws-provider'); const assert = require('@polkadot/util/assert'); const JsonRpcCoder = require('../jsonRpcCoder'); -module.exports = class WsProvider extends JsonRpcCoder implements ProviderInterface { +module.exports = class WsProvider extends JsonRpcCoder implements ProviderInterface$Subscribe { _autoConnect: boolean = true; _endpoint: string; - _handlers: { [number]: AwaitingType } = {}; + _handlers: { [number]: Awaiting } = {}; _isConnected: boolean = false; _queued: { [number]: string } = {}; _websocket: WebSocket; @@ -50,7 +51,8 @@ module.exports = class WsProvider extends JsonRpcCoder implements ProviderInterf } _onClose = () => { - // console.log('disconnected from', this._endpoint); + l.debug(() => ['disconnected from', this._endpoint]); + this._isConnected = false; if (this._autoConnect) { @@ -59,11 +61,12 @@ module.exports = class WsProvider extends JsonRpcCoder implements ProviderInterf } _onError = (error: Event) => { - console.error(error); + l.error(error); } _onOpen = () => { - // console.log('connected to', this._endpoint); + l.debug(() => ['connected to', this._endpoint]); + this._isConnected = true; Object.keys(this._queued).forEach((id) => { @@ -76,7 +79,7 @@ module.exports = class WsProvider extends JsonRpcCoder implements ProviderInterf // flowlint-next-line unclear-type:off delete this._queued[((id: any): number)]; } catch (error) { - console.error(error); + l.error(error); } }); } @@ -87,7 +90,7 @@ module.exports = class WsProvider extends JsonRpcCoder implements ProviderInterf const handler = this._handlers[response.id]; if (!handler) { - console.error(`Unable to find handler for id=${response.id}`); + l.error(`Unable to find handler for id=${response.id}`); return; } @@ -127,4 +130,12 @@ module.exports = class WsProvider extends JsonRpcCoder implements ProviderInterf } }); } + + subscribe (method: string, params: Array, cb: ProviderInterface$Subscribe$Callback): Promise { + throw new Error('Subscriptions has not been implemented'); + } + + unsubscribe (id: number): Promise { + throw new Error('Subscriptions has not been implemented'); + } }; diff --git a/packages/api-provider/src/ws/index.spec.js b/packages/api-provider/src/ws/index.spec.js index 80856c300e9d..6ff1c4d335d0 100644 --- a/packages/api-provider/src/ws/index.spec.js +++ b/packages/api-provider/src/ws/index.spec.js @@ -108,7 +108,9 @@ describe('Ws', () => { it('logs the error', () => { ws._onError('test error'); - expect(errorSpy).toHaveBeenCalledWith('test error'); + expect(errorSpy).toHaveBeenCalledWith( + expect.anything(), expect.anything(), 'test error' + ); }); }); @@ -116,7 +118,9 @@ describe('Ws', () => { it('fails with log when handler not found', () => { ws._onMessage({ data: '{"id":2}' }); - expect(errorSpy).toHaveBeenCalledWith('Unable to find handler for id=2'); + expect(errorSpy).toHaveBeenCalledWith( + expect.anything(), expect.anything(), 'Unable to find handler for id=2' + ); }); }); }); @@ -224,4 +228,22 @@ describe('Ws', () => { }); }); }); + + describe('pubsub', () => { + beforeEach(() => { + ws = createWs([]); + }); + + it('does not (yet) support subscribe', () => { + expect( + () => ws.subscribe() + ).toThrow(/has not been implemented/); + }); + + it('does not (yet) support unsubscribe', () => { + expect( + () => ws.unsubscribe() + ).toThrow(/has not been implemented/); + }); + }); }); diff --git a/packages/api/package.json b/packages/api/package.json index ad429d8612f0..45955d06d9da 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@polkadot/api", - "version": "0.7.1", + "version": "0.8.0", "description": "A JavaScript wrapper for the Polkadot JsonRPC interface", "main": "index.js", "keywords": [ @@ -30,10 +30,10 @@ "test": "echo \"Tests only available from root wrapper\"" }, "dependencies": { - "@polkadot/api-format": "^0.7.1", - "@polkadot/api-jsonrpc": "^0.7.1", - "@polkadot/api-provider": "^0.7.1", - "@polkadot/util": "^0.13.1", + "@polkadot/api-format": "^0.8.0", + "@polkadot/api-jsonrpc": "^0.8.0", + "@polkadot/api-provider": "^0.8.0", + "@polkadot/util": "^0.17.2", "babel-runtime": "^6.26.0" } } diff --git a/packages/api/src/api.js b/packages/api/src/api.js deleted file mode 100644 index 96c6a7a53235..000000000000 --- a/packages/api/src/api.js +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2017-2018 Jaco Greeff -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. -// @flow - -import type { ProviderInterface } from '@polkadot/api-provider/types'; -import type { ApiInterface, ApiInterface$Section } from './types'; - -const interfaces = require('@polkadot/api-jsonrpc'); -const assert = require('@polkadot/util/assert'); -const isFunction = require('@polkadot/util/is/function'); - -const createInterface = require('./create/interface'); - -module.exports = class Api implements ApiInterface { - chain: ApiInterface$Section; - state: ApiInterface$Section; - - constructor (provider: ProviderInterface) { - assert(provider && isFunction(provider.send), 'Expected Provider'); - - this.chain = createInterface(provider, interfaces.chain, 'chain'); - this.state = createInterface(provider, interfaces.state, 'state'); - } -}; diff --git a/packages/api/src/api.spec.js b/packages/api/src/api.spec.js deleted file mode 100644 index 3e99d4ce5c12..000000000000 --- a/packages/api/src/api.spec.js +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2017-2018 Jaco Greeff -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -const Api = require('./api'); - -describe('Api', () => { - let api; - let provider; - let sendSpy; - - beforeEach(() => { - provider = { - send: (method, params) => { - return Promise.resolve(params[0]); - } - }; - sendSpy = jest.spyOn(provider, 'send'); - api = new Api(provider); - }); - - afterEach(() => { - sendSpy.mockRestore(); - }); - - it('requires a provider with a send method', () => { - expect( - () => new Api({}) - ).toThrow(/Expected Provider/); - }); - - it('sets up the chain interface', () => { - expect(api.chain).toBeDefined(); - }); - - it('sets up the state interface', () => { - expect(api.state).toBeDefined(); - }); -}); diff --git a/packages/api/src/create/interface.js b/packages/api/src/create/interface.js index 29f06d627e0c..bd91eb2a8910 100644 --- a/packages/api/src/create/interface.js +++ b/packages/api/src/create/interface.js @@ -4,34 +4,31 @@ // @flow import type { InterfaceDefinition } from '@polkadot/api-jsonrpc/types'; -import type { ProviderInterface } from '@polkadot/api-provider/types'; +import type { ProviderInterface, ProviderInterface$Subscribe } from '@polkadot/api-provider/types'; import type { ApiInterface$Section } from '../types'; -const { formatInputs, formatOutput } = require('@polkadot/api-format'); -const assert = require('@polkadot/util/assert'); -const ExtError = require('@polkadot/util/ext/error'); -const jsonrpcSignature = require('@polkadot/util/jsonrpc/signature'); +const isFunction = require('@polkadot/util/is/function'); + +const createMethod = require('./method'); +const createSubscribe = require('./subscribe'); + +module.exports = function createInterface (provider: ProviderInterface, { methods }: InterfaceDefinition, section: string): ApiInterface$Section { + const exposed: $Shape = {}; + const pubsub = (provider: ProviderInterface$Subscribe); + + if (isFunction(pubsub.subscribe)) { + exposed.subscribe = createSubscribe(pubsub, section, methods); + exposed.unsubscribe = provider.unsubcribe; + } -module.exports = function createInterface (provider: ProviderInterface, definition: InterfaceDefinition, section: string): ApiInterface$Section { return Object - .keys(definition.methods) - .reduce((container, method: string) => { - const { inputs, output } = definition.methods[method]; - const rpcName = `${section}_${method}`; - - container[method] = async (..._params: Array): Promise => { - try { - assert(inputs.length === _params.length, `${inputs.length} params expected, found ${_params.length} instead`); - - const params = formatInputs(inputs, _params); - const result = await provider.send(rpcName, params); - - return formatOutput(output, result); - } catch (error) { - throw new ExtError(`${jsonrpcSignature(rpcName, inputs, output)}:: ${error.message}`, (error: ExtError).code); - } - }; - - return container; - }, ({}: $Shape)); + .keys(methods) + .reduce((exposed, name: string) => { + const rpcName = `${section}_${name}`; + const method = createMethod(provider, rpcName, methods[name]); + + exposed[name] = method; + + return exposed; + }, exposed); }; diff --git a/packages/api/src/create/interface.spec.js b/packages/api/src/create/interface.spec.js index faaabd336be0..72f943374a4a 100644 --- a/packages/api/src/create/interface.spec.js +++ b/packages/api/src/create/interface.spec.js @@ -33,42 +33,12 @@ describe('createInterface', () => { container = createInterface(provider, definition, 'test'); }); - describe('method expansion', () => { - it('adds the specified methods to the interface', () => { - expect(Object.keys(container)).toEqual(['blah', 'bleh']); - }); - - it('had function calls for the attached methods', () => { - expect(isFunction(container.blah)).toEqual(true); - expect(isFunction(container.bleh)).toEqual(true); - }); + it('adds the specified methods to the interface', () => { + expect(Object.keys(container)).toEqual(['blah', 'bleh']); }); - describe('calling', () => { - it('wraps errors with the call signature', () => { - return container - .blah() - .catch((error) => { - expect(error.message).toMatch(/test_blah \(foo: Address\): Address/); - }); - }); - - it('checks for mismatched parameters', () => { - return container - .bleh(1) - .catch((error) => { - expect(error.message).toMatch(/0 params expected, found 1 instead/); - }); - }); - - it('calls the provider with the correct parameters', () => { - return container - .blah('0x123') - .then(() => { - expect(provider.send).toHaveBeenCalledWith('test_blah', [ - '0x0123' - ]); - }); - }); + it('had function calls for the attached methods', () => { + expect(isFunction(container.blah)).toEqual(true); + expect(isFunction(container.bleh)).toEqual(true); }); }); diff --git a/packages/api/src/create/method.js b/packages/api/src/create/method.js new file mode 100644 index 000000000000..9cd0e2ca3add --- /dev/null +++ b/packages/api/src/create/method.js @@ -0,0 +1,28 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { InterfaceMethodDefinition } from '@polkadot/api-jsonrpc/types'; +import type { ProviderInterface } from '@polkadot/api-provider/types'; + +const formatOutput = require('@polkadot/api-format/output'); +const ExtError = require('@polkadot/util/ext/error'); +const jsonrpcSignature = require('@polkadot/util/jsonrpc/signature'); + +type Method = (..._params: Array) => Promise; + +const createParams = require('./params'); + +module.exports = function createMethod (provider: ProviderInterface, rpcName: string, { inputs, output }: InterfaceMethodDefinition): Method { + return async (..._params: Array): Promise => { + try { + const params = createParams(rpcName, _params, inputs); + const result = await provider.send(rpcName, params); + + return formatOutput(output, result); + } catch (error) { + throw new ExtError(`${jsonrpcSignature(rpcName, inputs, output)}:: ${error.message}`, (error: ExtError).code); + } + }; +}; diff --git a/packages/api/src/create/method.spec.js b/packages/api/src/create/method.spec.js new file mode 100644 index 000000000000..f207726085ab --- /dev/null +++ b/packages/api/src/create/method.spec.js @@ -0,0 +1,55 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const createMethod = require('./method'); + +describe('createMethod', () => { + let methods; + let provider; + + beforeEach(() => { + methods = { + blah: { + inputs: [ + { name: 'foo', type: 'Address' } + ], + output: { type: 'Address' } + }, + bleh: { + inputs: [], + output: { type: 'Address' } + } + }; + + provider = { + send: jest.fn((method, params) => { + return Promise.resolve(params[0]); + }) + }; + }); + + it('wraps errors with the call signature', () => { + const method = createMethod(provider, 'test_blah', methods.blah); + + return method().catch((error) => { + expect(error.message).toMatch(/test_blah \(foo: Address\): Address/); + }); + }); + + it('checks for mismatched parameters', () => { + const method = createMethod(provider, 'test_bleh', methods.bleh); + + return method(1).catch((error) => { + expect(error.message).toMatch(/0 params expected, found 1 instead/); + }); + }); + + it('calls the provider with the correct parameters', () => { + const method = createMethod(provider, 'test_blah', methods.blah); + + return method(new Uint8Array([0x12, 0x34])).then(() => { + expect(provider.send).toHaveBeenCalledWith('test_blah', ['0x1234']); + }); + }); +}); diff --git a/packages/api/src/create/params.js b/packages/api/src/create/params.js new file mode 100644 index 000000000000..7ad1869e5d08 --- /dev/null +++ b/packages/api/src/create/params.js @@ -0,0 +1,15 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { InterfaceInputType } from '@polkadot/api-jsonrpc/types'; + +const formatInputs = require('@polkadot/api-format/input'); +const assert = require('@polkadot/util/assert'); + +module.exports = function createParams (rpcName: string, params: Array, inputs: Array): Array { + assert(inputs.length === params.length, `${rpcName}: ${inputs.length} params expected, found ${params.length} instead`); + + return formatInputs(inputs, params); +}; diff --git a/packages/api/src/create/subscribe.js b/packages/api/src/create/subscribe.js new file mode 100644 index 000000000000..b2016830be0e --- /dev/null +++ b/packages/api/src/create/subscribe.js @@ -0,0 +1,40 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { InterfaceDefinition$Methods } from '@polkadot/api-jsonrpc/types'; +import type { ProviderInterface$Subscribe, ProviderInterface$Subscribe$Callback } from '@polkadot/api-provider/types'; + +const formatOutput = require('@polkadot/api-format/output'); +const ExtError = require('@polkadot/util/ext/error'); +const assert = require('@polkadot/util/assert'); +const jsonrpcSignature = require('@polkadot/util/jsonrpc/signature'); + +type Method = (..._params: Array) => Promise; + +const createParams = require('./params'); + +module.exports = function createSubscribe (provider: ProviderInterface$Subscribe, methods: InterfaceDefinition$Methods, section: string): Method { + return async (name: string, _params: Array, cb: ProviderInterface$Subscribe$Callback): Promise => { + const rpcName = `${section}_${name}`; + + assert(methods[name], `Unable to find '${rpcName}' subscription`); + + const { inputs, output } = methods[name]; + + try { + const params = createParams(rpcName, _params, inputs); + + return provider.subscribe(rpcName, params, (error: ?Error, result: mixed) => { + if (error) { + cb(error); + } else { + cb(null, formatOutput(output, result)); + } + }); + } catch (error) { + throw new ExtError(`${jsonrpcSignature(rpcName, inputs, output)}:: ${error.message}`, (error: ExtError).code); + } + }; +}; diff --git a/packages/api/src/create/subscribe.spec.js b/packages/api/src/create/subscribe.spec.js new file mode 100644 index 000000000000..a4a3dc2c3af0 --- /dev/null +++ b/packages/api/src/create/subscribe.spec.js @@ -0,0 +1,70 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const createSubscribe = require('./subscribe'); + +describe('createSubscribe', () => { + let methods; + let provider; + let sub; + let cb; + + beforeEach(() => { + methods = { + blah: { + inputs: [ + { name: 'foo', type: 'Address' } + ], + output: { type: 'Address' } + }, + bleh: { + inputs: [], + output: { type: 'Address' } + } + }; + + provider = { + subscribe: jest.fn((method, params, _cb) => { + cb = _cb; + + return Promise.resolve(12345); + }), + unsubscribe: jest.fn(() => { + return Promise.resolve(true); + }) + }; + + sub = createSubscribe(provider, methods, 'test'); + }); + + it('it does not subscribe to not-found endpoint', () => { + return sub('notFound').catch((error) => { + expect(error.message).toMatch(/Unable to find 'test_notFound' subscription/); + }); + }); + + it('returns the subscription', () => { + return sub('bleh', []).then((id) => { + expect(id).toEqual(12345); + }); + }); + + it('returns values as they are available', (done) => { + sub('bleh', [], () => { + done(); + }); + + cb(null, '0x123'); + }); + + it('returns errors as they are available', (done) => { + sub('bleh', [], (error) => { + expect(error.message).toEqual('test error'); + + done(); + }); + + cb(new Error('test error')); + }); +}); diff --git a/packages/api/src/index.js b/packages/api/src/index.js index 7e99e8bab079..696ecd91af81 100644 --- a/packages/api/src/index.js +++ b/packages/api/src/index.js @@ -3,6 +3,20 @@ // of the ISC license. See the LICENSE file for details. // @flow -const Api = require('./api'); +import type { ProviderInterface } from '@polkadot/api-provider/types'; +import type { ApiInterface } from './types'; -module.exports = Api; +const interfaces = require('@polkadot/api-jsonrpc'); +const assert = require('@polkadot/util/assert'); +const isFunction = require('@polkadot/util/is/function'); + +const createInterface = require('./create/interface'); + +module.exports = function api (provider: ProviderInterface): ApiInterface { + assert(provider && isFunction(provider.send), 'Expected Provider'); + + return { + chain: createInterface(provider, interfaces.chain, 'chain'), + state: createInterface(provider, interfaces.state, 'state') + }; +}; diff --git a/packages/api/src/index.spec.js b/packages/api/src/index.spec.js index 8055e1c769bd..132c41f5133f 100644 --- a/packages/api/src/index.spec.js +++ b/packages/api/src/index.spec.js @@ -2,10 +2,38 @@ // This software may be modified and distributed under the terms // of the ISC license. See the LICENSE file for details. -const Api = require('./index'); +const createApi = require('./index'); -describe('index', () => { - it('exports default Api', () => { - expect(Api).toBeDefined(); +describe('Api', () => { + let api; + let provider; + let sendSpy; + + beforeEach(() => { + provider = { + send: (method, params) => { + return Promise.resolve(params[0]); + } + }; + sendSpy = jest.spyOn(provider, 'send'); + api = createApi(provider); + }); + + afterEach(() => { + sendSpy.mockRestore(); + }); + + it('requires a provider with a send method', () => { + expect( + () => createApi({}) + ).toThrow(/Expected Provider/); + }); + + it('sets up the chain interface', () => { + expect(api.chain).toBeDefined(); + }); + + it('sets up the state interface', () => { + expect(api.state).toBeDefined(); }); }); diff --git a/packages/api/src/types.js b/packages/api/src/types.js index cd18f8c82612..a8d47a55e601 100644 --- a/packages/api/src/types.js +++ b/packages/api/src/types.js @@ -7,7 +7,7 @@ export type ApiInterface$Section = { [string]: () => Promise }; -export interface ApiInterface { - +chain: ApiInterface$Section; - +state: ApiInterface$Section; +export type ApiInterface = { + chain: ApiInterface$Section, + state: ApiInterface$Section } diff --git a/yarn.lock b/yarn.lock index cd1b9942dacc..327325a155bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,13 +2,11 @@ # yarn lockfile v1 -"@babel/code-frame@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz#473d021ecc573a2cce1c07d5b509d5215f46ba35" +"@babel/code-frame@7.0.0-beta.40", "@babel/code-frame@^7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz#37e2b0cf7c56026b4b21d3927cadf81adec32ac6" dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^3.0.0" + "@babel/highlight" "7.0.0-beta.40" "@babel/code-frame@^7.0.0-beta.35": version "7.0.0-beta.36" @@ -18,58 +16,76 @@ esutils "^2.0.2" js-tokens "^3.0.0" -"@babel/helper-function-name@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.31.tgz#afe63ad799209989348b1109b44feb66aa245f57" +"@babel/generator@7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.40.tgz#ab61f9556f4f71dbd1138949c795bb9a21e302ea" + dependencies: + "@babel/types" "7.0.0-beta.40" + jsesc "^2.5.1" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.40.tgz#9d033341ab16517f40d43a73f2d81fc431ccd7b6" dependencies: - "@babel/helper-get-function-arity" "7.0.0-beta.31" - "@babel/template" "7.0.0-beta.31" - "@babel/traverse" "7.0.0-beta.31" - "@babel/types" "7.0.0-beta.31" + "@babel/helper-get-function-arity" "7.0.0-beta.40" + "@babel/template" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.40" -"@babel/helper-get-function-arity@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.31.tgz#1176d79252741218e0aec872ada07efb2b37a493" +"@babel/helper-get-function-arity@7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.40.tgz#ac0419cf067b0ec16453e1274f03878195791c6e" dependencies: - "@babel/types" "7.0.0-beta.31" + "@babel/types" "7.0.0-beta.40" -"@babel/template@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.31.tgz#577bb29389f6c497c3e7d014617e7d6713f68bda" +"@babel/highlight@7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.40.tgz#b43d67d76bf46e1d10d227f68cddcd263786b255" dependencies: - "@babel/code-frame" "7.0.0-beta.31" - "@babel/types" "7.0.0-beta.31" - babylon "7.0.0-beta.31" + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/template@7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.40.tgz#034988c6424eb5c3268fe6a608626de1f4410fc8" + dependencies: + "@babel/code-frame" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.40" + babylon "7.0.0-beta.40" lodash "^4.2.0" -"@babel/traverse@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.31.tgz#db399499ad74aefda014f0c10321ab255134b1df" +"@babel/traverse@^7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.40.tgz#d140e449b2e093ef9fe1a2eecc28421ffb4e521e" dependencies: - "@babel/code-frame" "7.0.0-beta.31" - "@babel/helper-function-name" "7.0.0-beta.31" - "@babel/types" "7.0.0-beta.31" - babylon "7.0.0-beta.31" + "@babel/code-frame" "7.0.0-beta.40" + "@babel/generator" "7.0.0-beta.40" + "@babel/helper-function-name" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.40" + babylon "7.0.0-beta.40" debug "^3.0.1" - globals "^10.0.0" + globals "^11.1.0" invariant "^2.2.0" lodash "^4.2.0" -"@babel/types@7.0.0-beta.31": - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.31.tgz#42c9c86784f674c173fb21882ca9643334029de4" +"@babel/types@7.0.0-beta.40", "@babel/types@^7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.40.tgz#25c3d7aae14126abe05fcb098c65a66b6d6b8c14" dependencies: esutils "^2.0.2" lodash "^4.2.0" to-fast-properties "^2.0.0" -"@polkadot/dev@^0.15.1": - version "0.15.1" - resolved "https://registry.yarnpkg.com/@polkadot/dev/-/dev-0.15.1.tgz#74b764552ae7c11cbf35797abd389148033fe562" +"@polkadot/dev@^0.16.17": + version "0.16.17" + resolved "https://registry.yarnpkg.com/@polkadot/dev/-/dev-0.16.17.tgz#530653a5659a9d6a0784aeed99b219ee3a56d340" dependencies: babel-cli "^6.26.0" babel-core "^6.26.0" - babel-eslint "^8.1.2" + babel-eslint "^8.2.2" babel-plugin-transform-class-properties "^6.24.1" babel-plugin-transform-flow-strip-types "^6.22.0" babel-plugin-transform-object-rest-spread "^6.26.0" @@ -77,47 +93,115 @@ babel-preset-env "^1.6.1" coveralls "^3.0.0" dox "^0.9.0" - eslint "^4.14.0" - eslint-config-semistandard "^12.0.0" - eslint-config-standard "^11.0.0-beta.0" - eslint-config-standard-jsx "^4.0.2" - eslint-config-standard-react "^5.0.0" - eslint-plugin-flowtype "^2.39.1" - eslint-plugin-import "^2.8.0" - eslint-plugin-jest "^21.3.2" - eslint-plugin-node "^5.2.1" + eslint "^4.18.2" + eslint-config-semistandard "^12.0.1" + eslint-config-standard "^11.0.0" + eslint-config-standard-jsx "^5.0.0" + eslint-config-standard-react "^6.0.0" + eslint-plugin-flowtype "^2.46.1" + eslint-plugin-import "^2.9.0" + eslint-plugin-jest "^21.13.0" + eslint-plugin-node "^6.0.1" eslint-plugin-promise "^3.6.0" - eslint-plugin-react "^7.4.0" + eslint-plugin-react "^7.7.0" eslint-plugin-standard "^3.0.1" - flow-bin "^0.64.0" - flow-copy-source "^1.2.1" - jest "^22.0.0" + flow-bin "^0.67.1" + flow-copy-source "^1.3.0" + jest "^22.4.2" makeshift "^1.1.0" mkdirp "^0.5.1" - postcss "^6.0.14" + postcss "^6.0.19" postcss-sass "^0.3.0" rimraf "^2.6.2" - stylelint "^8.2.0" - stylelint-config-standard "^18.0.0" + stylelint "^9.1.1" + stylelint-config-standard "^18.2.0" + +"@polkadot/primitives-builder@^0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@polkadot/primitives-builder/-/primitives-builder-0.9.4.tgz#14925b6c2d18d90c016ad16f43707eb6f83000c7" + dependencies: + "@polkadot/primitives" "^0.9.4" + "@polkadot/primitives-codec" "^0.9.4" + "@polkadot/util" "^0.17.2" + "@polkadot/util-crypto" "^0.17.2" + "@polkadot/util-triehash" "^0.17.2" + babel-runtime "^6.26.0" + +"@polkadot/primitives-codec@^0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@polkadot/primitives-codec/-/primitives-codec-0.9.4.tgz#8dea2bfc0c8583d151b2f9b96ceec0c8a43be41f" + dependencies: + "@polkadot/primitives" "^0.9.4" + "@polkadot/primitives-builder" "^0.9.4" + "@polkadot/primitives-rlp" "^0.9.4" + "@polkadot/util" "^0.17.2" + "@polkadot/util-keyring" "^0.17.2" + babel-runtime "^6.26.0" + +"@polkadot/primitives-json@^0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@polkadot/primitives-json/-/primitives-json-0.9.4.tgz#9cc0d4a90cf56e6d6058d44849930b396af0fa62" + dependencies: + "@polkadot/primitives" "^0.9.4" + "@polkadot/primitives-builder" "^0.9.4" + "@polkadot/util" "^0.17.2" + babel-runtime "^6.26.0" + +"@polkadot/primitives-rlp@^0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@polkadot/primitives-rlp/-/primitives-rlp-0.9.4.tgz#a0e62f670515d43932961be74f4dcb12a6bbe2bf" + dependencies: + "@polkadot/primitives" "^0.9.4" + "@polkadot/primitives-builder" "^0.9.4" + "@polkadot/primitives-json" "^0.9.4" + "@polkadot/util" "^0.17.2" + "@polkadot/util-crypto" "^0.17.2" + babel-runtime "^6.26.0" + +"@polkadot/primitives@^0.9.4": + version "0.9.4" + resolved "https://registry.yarnpkg.com/@polkadot/primitives/-/primitives-0.9.4.tgz#fd4993238c2e8570d96182c1aa35a89b20d30eb0" + dependencies: + "@polkadot/util" "^0.17.2" + babel-runtime "^6.26.0" + +"@polkadot/util-crypto@^0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@polkadot/util-crypto/-/util-crypto-0.17.2.tgz#014e5d6d13461420907a06d5f316ce9906f825bc" + dependencies: + babel-runtime "^6.26.0" + blakejs "^1.1.0" + js-sha3 "^0.7.0" + tweetnacl "^1.0.0" + xxhashjs "^0.2.2" -"@polkadot/primitives-json@^0.4.10": - version "0.4.10" - resolved "https://registry.yarnpkg.com/@polkadot/primitives-json/-/primitives-json-0.4.10.tgz#93ecf3d1ccd178bcbb11d8721fd323bf3d161df3" +"@polkadot/util-keyring@^0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@polkadot/util-keyring/-/util-keyring-0.17.2.tgz#f759803634c7285b24794c410d9ec38f1964c923" dependencies: - "@polkadot/primitives" "^0.4.10" - "@polkadot/util" "^0.13.1" + "@polkadot/util" "^0.17.2" + "@polkadot/util-crypto" "^0.17.2" babel-runtime "^6.26.0" -"@polkadot/primitives@^0.4.10": - version "0.4.10" - resolved "https://registry.yarnpkg.com/@polkadot/primitives/-/primitives-0.4.10.tgz#5ec557cf0ecdb608697d31e3ac17224bedd90572" +"@polkadot/util-rlp@^0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@polkadot/util-rlp/-/util-rlp-0.17.2.tgz#1f2cced179c6aad9f48b7ff3e9cee86e1edfce21" dependencies: - "@polkadot/util" "^0.13.1" + "@polkadot/util" "^0.17.2" babel-runtime "^6.26.0" -"@polkadot/util@^0.13.1": - version "0.13.1" - resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-0.13.1.tgz#17373a04e8310f2a06ffcf3e4cc7b47eb7693be8" +"@polkadot/util-triehash@^0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@polkadot/util-triehash/-/util-triehash-0.17.2.tgz#4bb6cd32fb6ca42b73563bdb7c9ac5ffa929728e" + dependencies: + "@polkadot/util" "^0.17.2" + "@polkadot/util-crypto" "^0.17.2" + "@polkadot/util-rlp" "^0.17.2" + babel-runtime "^6.26.0" + +"@polkadot/util@^0.17.2": + version "0.17.2" + resolved "https://registry.yarnpkg.com/@polkadot/util/-/util-0.17.2.tgz#f37a989c15f30d706d036da02c5d1699b8abcecb" dependencies: babel-runtime "^6.26.0" bn.js "^4.11.8" @@ -232,6 +316,13 @@ anymatch@^1.3.0: micromatch "^2.1.5" normalize-path "^2.0.0" +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + append-transform@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" @@ -261,10 +352,18 @@ arr-diff@^2.0.0: dependencies: arr-flatten "^1.0.1" -arr-flatten@^1.0.1: +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + array-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" @@ -302,6 +401,10 @@ array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -326,6 +429,10 @@ assertion-error@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" @@ -348,15 +455,19 @@ asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" -autoprefixer@^7.1.2: - version "7.1.6" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-7.1.6.tgz#fb933039f74af74a83e71225ce78d9fd58ba84d7" +atob@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d" + +autoprefixer@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-8.0.0.tgz#c19e480f061013127c373df0b01cf46919943f74" dependencies: - browserslist "^2.5.1" - caniuse-lite "^1.0.30000748" + browserslist "^3.0.0" + caniuse-lite "^1.0.30000808" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^6.0.13" + postcss "^6.0.17" postcss-value-parser "^3.2.3" aws-sign2@~0.6.0: @@ -424,14 +535,14 @@ babel-core@^6.0.0, babel-core@^6.26.0: slash "^1.0.0" source-map "^0.5.6" -babel-eslint@^8.1.2: - version "8.1.2" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.1.2.tgz#a39230b0c20ecbaa19a35d5633bf9b9ca2c8116f" +babel-eslint@^8.2.2: + version "8.2.2" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.2.tgz#1102273354c6f0b29b4ea28a65f97d122296b68b" dependencies: - "@babel/code-frame" "7.0.0-beta.31" - "@babel/traverse" "7.0.0-beta.31" - "@babel/types" "7.0.0-beta.31" - babylon "7.0.0-beta.31" + "@babel/code-frame" "^7.0.0-beta.40" + "@babel/traverse" "^7.0.0-beta.40" + "@babel/types" "^7.0.0-beta.40" + babylon "^7.0.0-beta.40" eslint-scope "~3.7.1" eslint-visitor-keys "^1.0.0" @@ -549,12 +660,12 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-jest@^22.0.4: - version "22.0.4" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-22.0.4.tgz#533c46de37d7c9d7612f408c76314be9277e0c26" +babel-jest@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-22.4.1.tgz#ff53ebca45957347f27ff4666a31499fbb4c4ddd" dependencies: babel-plugin-istanbul "^4.1.5" - babel-preset-jest "^22.0.3" + babel-preset-jest "^22.4.1" babel-messages@^6.23.0: version "6.23.0" @@ -576,9 +687,9 @@ babel-plugin-istanbul@^4.1.5: istanbul-lib-instrument "^1.7.5" test-exclude "^4.1.1" -babel-plugin-jest-hoist@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.0.3.tgz#62cde5fe962fd41ae89c119f481ca5cd7dd48bb4" +babel-plugin-jest-hoist@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-22.4.1.tgz#d712fe5da8b6965f3191dacddbefdbdf4fb66d63" babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" @@ -873,11 +984,11 @@ babel-preset-env@^1.6.1: invariant "^2.2.2" semver "^5.3.0" -babel-preset-jest@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.0.3.tgz#e2bb6f6b4a509d3ea0931f013db78c5a84856693" +babel-preset-jest@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-22.4.1.tgz#efa2e5f5334242a9457a068452d7d09735db172a" dependencies: - babel-plugin-jest-hoist "^22.0.3" + babel-plugin-jest-hoist "^22.4.1" babel-plugin-syntax-object-rest-spread "^6.13.0" babel-register@^6.26.0: @@ -932,9 +1043,9 @@ babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26 lodash "^4.17.4" to-fast-properties "^1.0.3" -babylon@7.0.0-beta.31: - version "7.0.0-beta.31" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.31.tgz#7ec10f81e0e456fd0f855ad60fa30c2ac454283f" +babylon@7.0.0-beta.40, babylon@^7.0.0-beta.40: + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.40.tgz#91fc8cd56d5eb98b28e6fde41045f2957779940a" babylon@^6.18.0: version "6.18.0" @@ -948,6 +1059,18 @@ balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + bcrypt-pbkdf@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" @@ -958,14 +1081,14 @@ binary-extensions@^1.0.0: version "1.11.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.11.0.tgz#46aa1751fb6a2f93ee5e689bb1087d4b14c6c205" -bindings@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" - bindings@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11" +blakejs@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" + block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" @@ -1013,6 +1136,23 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" +braces@^2.3.0, braces@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.1.tgz#7086c913b4e5a08dbe37ac0ee6a2500c4ba691bb" + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + define-property "^1.0.0" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + kind-of "^6.0.2" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + browser-process-hrtime@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e" @@ -1023,13 +1163,20 @@ browser-resolve@^1.11.2: dependencies: resolve "1.1.7" -browserslist@^2.1.2, browserslist@^2.5.1: +browserslist@^2.1.2: version "2.9.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.9.1.tgz#b72d3982ab01b5cd24da62ff6d45573886aff275" dependencies: caniuse-lite "^1.0.30000770" electron-to-chromium "^1.3.27" +browserslist@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-3.1.1.tgz#d380fc048bc3a33e60fb87dc135110ebaaa6320a" + dependencies: + caniuse-lite "^1.0.30000809" + electron-to-chromium "^1.3.33" + bser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719" @@ -1044,6 +1191,20 @@ byline@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -1065,6 +1226,14 @@ camelcase-keys@^2.0.0: camelcase "^2.0.0" map-obj "^1.0.0" +camelcase-keys@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" + dependencies: + camelcase "^4.1.0" + map-obj "^2.0.0" + quick-lru "^1.0.0" + camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" @@ -1077,10 +1246,14 @@ camelcase@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" -caniuse-lite@^1.0.30000748, caniuse-lite@^1.0.30000770: +caniuse-lite@^1.0.30000770: version "1.0.30000772" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000772.tgz#78129622cabfed7af1ff38b64ab680a6a0865420" +caniuse-lite@^1.0.30000808, caniuse-lite@^1.0.30000809: + version "1.0.30000809" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000809.tgz#1e12c1344b8f74d56737ee2614bcedb648943479" + capture-stack-trace@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz#4a6fa07399c26bba47f0b2496b4d0fb408c5550d" @@ -1126,6 +1299,14 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" +chalk@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796" + dependencies: + ansi-styles "^3.2.0" + escape-string-regexp "^1.0.5" + supports-color "^5.2.0" + character-entities-html4@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.1.tgz#359a2a4a0f7e29d3dc2ac99bdbe21ee39438ea50" @@ -1146,7 +1327,7 @@ chardet@^0.4.0: version "0.4.2" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" -chokidar@^1.6.1, chokidar@^1.7.0: +chokidar@^1.6.1: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: @@ -1161,6 +1342,24 @@ chokidar@^1.6.1, chokidar@^1.7.0: optionalDependencies: fsevents "^1.0.0" +chokidar@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.2.tgz#4dc65139eeb2714977735b6a35d06e97b494dfd7" + dependencies: + anymatch "^2.0.0" + async-each "^1.0.0" + braces "^2.3.0" + glob-parent "^3.1.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^2.1.1" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + upath "^1.0.0" + optionalDependencies: + fsevents "^1.0.0" + ci-info@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.2.tgz#03561259db48d0474c8bdc90f5b47b068b6bbfb4" @@ -1169,6 +1368,15 @@ circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + cli-cursor@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" @@ -1195,6 +1403,14 @@ cliui@^3.2.0: strip-ansi "^3.0.1" wrap-ansi "^2.0.0" +cliui@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.0.0.tgz#743d4650e05f36d1ed2575b59638d87322bfbbcc" + dependencies: + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + clone-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-1.0.0.tgz#eae0a2413f55c0942f818c229fefce845d7f3b1c" @@ -1225,6 +1441,13 @@ collapse-white-space@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.3.tgz#4b906f670e5a963a87b76b0e1689643341b6023c" +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + color-convert@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed" @@ -1269,6 +1492,10 @@ compare-func@^1.3.1: array-ify "^1.0.0" dot-prop "^3.0.0" +component-emitter@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1442,6 +1669,10 @@ 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" +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -1454,13 +1685,13 @@ 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" -cosmiconfig@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-3.1.0.tgz#640a94bf9847f321800403cd273af60665c73397" +cosmiconfig@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-4.0.0.tgz#760391549580bbd2df1e562bc177b13c290972dc" dependencies: is-directory "^0.3.1" js-yaml "^3.9.0" - parse-json "^3.0.0" + parse-json "^4.0.0" require-from-string "^2.0.1" coveralls@^3.0.0: @@ -1509,6 +1740,10 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": dependencies: cssom "0.3.x" +cuint@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b" + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -1541,7 +1776,7 @@ deasync@^0.1.12: bindings "~1.2.1" nan "^2.0.7" -debug@^2.2.0, debug@^2.6.8: +debug@^2.2.0, debug@^2.3.3, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -1553,10 +1788,21 @@ debug@^3.0.0, debug@^3.0.1, debug@^3.1.0: dependencies: ms "2.0.0" -decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: +decamelize-keys@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +decamelize@^1.0.0, decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -1598,6 +1844,25 @@ define-properties@^1.1.2: foreach "^2.0.5" object-keys "^1.0.8" +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + del@^2.0.2: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" @@ -1654,12 +1919,18 @@ doctrine@1.5.0: esutils "^2.0.2" isarray "^1.0.0" -doctrine@^2.0.0, doctrine@^2.0.2: +doctrine@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.2.tgz#68f96ce8efc56cc42651f1faadb4f175273b0075" dependencies: esutils "^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" + dom-serializer@0: version "0.1.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" @@ -1730,6 +2001,10 @@ electron-to-chromium@^1.3.27: version "1.3.27" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz#78ecb8a399066187bb374eede35d9c70565a803d" +electron-to-chromium@^1.3.33: + version "1.3.33" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.33.tgz#bf00703d62a7c65238136578c352d6c5c042a545" + encoding@^0.1.11: version "0.1.12" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" @@ -1779,23 +2054,23 @@ escodegen@^1.9.0: optionalDependencies: source-map "~0.5.6" -eslint-config-semistandard@^12.0.0: - version "12.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-semistandard/-/eslint-config-semistandard-12.0.0.tgz#e6482de68e05c2dbdddaf45c3078f6a97fe23f1a" +eslint-config-semistandard@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/eslint-config-semistandard/-/eslint-config-semistandard-12.0.1.tgz#e35d66959dfe6f0d8e8445d7a4de37d8fd8875f4" -eslint-config-standard-jsx@^4.0.0, eslint-config-standard-jsx@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.2.tgz#009e53c4ddb1e9ee70b4650ffe63a7f39f8836e1" - -eslint-config-standard-react@^5.0.0: +eslint-config-standard-jsx@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/eslint-config-standard-react/-/eslint-config-standard-react-5.0.0.tgz#64c7b8140172852be810a53d48ee87649ff178e3" + resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-5.0.0.tgz#4abfac554f38668e0078c664569e7b2384e5d2aa" + +eslint-config-standard-react@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard-react/-/eslint-config-standard-react-6.0.0.tgz#d366d6c3c092426fd3ae794a4ca0b3cb131f2964" dependencies: - eslint-config-standard-jsx "^4.0.0" + eslint-config-standard-jsx "^5.0.0" -eslint-config-standard@^11.0.0-beta.0: - version "11.0.0-beta.0" - resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-11.0.0-beta.0.tgz#f8afe69803d95c685a4b8392b8793188eb03cbb3" +eslint-config-standard@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-11.0.0.tgz#87ee0d3c9d95382dc761958cbb23da9eea31e0ba" eslint-import-resolver-node@^0.3.1: version "0.3.1" @@ -1811,15 +2086,15 @@ eslint-module-utils@^2.1.1: debug "^2.6.8" pkg-dir "^1.0.0" -eslint-plugin-flowtype@^2.39.1: - version "2.39.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.39.1.tgz#b5624622a0388bcd969f4351131232dcb9649cd5" +eslint-plugin-flowtype@^2.46.1: + version "2.46.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-2.46.1.tgz#c4f81d580cd89c82bc3a85a1ccf4ae3a915143a4" dependencies: lodash "^4.15.0" -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" +eslint-plugin-import@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz#26002efbfca5989b7288ac047508bd24f217b169" dependencies: builtin-modules "^1.1.1" contains-path "^0.1.0" @@ -1828,34 +2103,34 @@ eslint-plugin-import@^2.8.0: eslint-import-resolver-node "^0.3.1" eslint-module-utils "^2.1.1" has "^1.0.1" - lodash.cond "^4.3.0" + lodash "^4.17.4" minimatch "^3.0.3" read-pkg-up "^2.0.0" -eslint-plugin-jest@^21.3.2: - version "21.3.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.3.2.tgz#b1cefc05f0fed700eb40185a94d16f6d575d1ef9" +eslint-plugin-jest@^21.13.0: + version "21.13.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.13.0.tgz#9fc903158d79e953aefd861a55e8a8c9f6ab3d36" -eslint-plugin-node@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-5.2.1.tgz#80df3253c4d7901045ec87fa660a284e32bdca29" +eslint-plugin-node@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-6.0.1.tgz#bf19642298064379315d7a4b2a75937376fa05e4" dependencies: ignore "^3.3.6" minimatch "^3.0.4" resolve "^1.3.3" - semver "5.3.0" + semver "^5.4.1" eslint-plugin-promise@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.6.0.tgz#54b7658c8f454813dc2a870aff8152ec4969ba75" -eslint-plugin-react@^7.4.0: - version "7.5.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.5.1.tgz#52e56e8d80c810de158859ef07b880d2f56ee30b" +eslint-plugin-react@^7.7.0: + version "7.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz#f606c719dbd8a1a2b3d25c16299813878cca0160" dependencies: - doctrine "^2.0.0" + doctrine "^2.0.2" has "^1.0.1" - jsx-ast-utils "^2.0.0" + jsx-ast-utils "^2.0.1" prop-types "^15.6.0" eslint-plugin-standard@^3.0.1: @@ -1873,9 +2148,9 @@ 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.14.0: - version "4.14.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.14.0.tgz#96609768d1dd23304faba2d94b7fefe5a5447a82" +eslint@^4.18.2: + version "4.18.2" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.18.2.tgz#0f81267ad1012e7d2051e186a9004cc2267b8d45" dependencies: ajv "^5.3.0" babel-code-frame "^6.22.0" @@ -1883,7 +2158,7 @@ eslint@^4.14.0: concat-stream "^1.6.0" cross-spawn "^5.1.0" debug "^3.1.0" - doctrine "^2.0.2" + doctrine "^2.1.0" eslint-scope "^3.7.1" eslint-visitor-keys "^1.0.0" espree "^3.5.2" @@ -1912,7 +2187,7 @@ eslint@^4.14.0: semver "^5.3.0" strip-ansi "^4.0.0" strip-json-comments "~2.0.1" - table "^4.0.1" + table "4.0.2" text-table "~0.2.0" espree@^3.5.2: @@ -1987,28 +2262,57 @@ execall@^1.0.0: dependencies: clone-regexp "^1.0.0" +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" dependencies: is-posix-bracket "^0.1.0" +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + expand-range@^1.8.1: version "1.8.2" resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" dependencies: fill-range "^2.1.0" -expect@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/expect/-/expect-22.0.3.tgz#bb486de7d41bf3eb60d3b16dfd1c158a4d91ddfa" +expect@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-22.4.0.tgz#371edf1ae15b83b5bf5ec34b42f1584660a36c16" dependencies: ansi-styles "^3.2.0" - jest-diff "^22.0.3" - jest-get-type "^22.0.3" - jest-matcher-utils "^22.0.3" - jest-message-util "^22.0.3" - jest-regex-util "^22.0.3" + jest-diff "^22.4.0" + jest-get-type "^22.1.0" + jest-matcher-utils "^22.4.0" + jest-message-util "^22.4.0" + jest-regex-util "^22.1.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: version "3.0.1" @@ -2028,6 +2332,19 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + extsprintf@1.3.0, extsprintf@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -2096,6 +2413,15 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -2118,21 +2444,21 @@ flat-cache@^1.2.1: graceful-fs "^4.1.2" write "^0.2.1" -flow-bin@^0.64.0: - version "0.64.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.64.0.tgz#ddd3fb3b183ab1ab35a5d5dec9caf5ebbcded167" +flow-bin@^0.67.1: + version "0.67.1" + resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.67.1.tgz#eabb7197cce870ac9442cfd04251c7ddc30377db" -flow-copy-source@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/flow-copy-source/-/flow-copy-source-1.2.1.tgz#705c2fa8fb29a281118e1c4b66218dec24b745ec" +flow-copy-source@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/flow-copy-source/-/flow-copy-source-1.3.0.tgz#591b153f5c01e8fc566c64a97290ea9103b7f1ea" dependencies: - chokidar "^1.7.0" - fs-extra "^3.0.1" + chokidar "^2.0.0" + fs-extra "^5.0.0" glob "^7.0.0" kefir "^3.7.3" - yargs "^8.0.2" + yargs "^11.0.0" -for-in@^1.0.1: +for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -2166,13 +2492,11 @@ form-data@~2.3.1: combined-stream "^1.0.5" mime-types "^2.1.12" -fs-extra@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" dependencies: - graceful-fs "^4.1.2" - jsonfile "^3.0.0" - universalify "^0.1.0" + map-cache "^0.2.2" fs-extra@^4.0.1: version "4.0.2" @@ -2182,6 +2506,14 @@ fs-extra@^4.0.1: jsonfile "^4.0.0" universalify "^0.1.0" +fs-extra@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-readdir-recursive@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" @@ -2265,6 +2597,10 @@ get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + getpass@^0.1.1: version "0.1.7" resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" @@ -2332,14 +2668,14 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2: once "^1.3.0" path-is-absolute "^1.0.0" -globals@^10.0.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-10.4.0.tgz#5c477388b128a9e4c5c5d01c7a2aca68c68b2da7" - globals@^11.0.1: version "11.0.1" resolved "https://registry.yarnpkg.com/globals/-/globals-11.0.1.tgz#12a87bb010e5154396acc535e1e43fc753b0e5e8" +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" @@ -2460,10 +2796,41 @@ 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" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + has@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" @@ -2552,6 +2919,13 @@ ignore@^3.3.3, ignore@^3.3.5, ignore@^3.3.6: version "3.3.7" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" +import-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" + dependencies: + pkg-dir "^2.0.0" + resolve-cwd "^2.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -2562,6 +2936,10 @@ indent-string@^2.1.0: dependencies: repeating "^2.0.0" +indent-string@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" + indexes-of@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" @@ -2614,6 +2992,18 @@ ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + dependencies: + kind-of "^6.0.0" + is-alphabetical@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.1.tgz#c77079cc91d4efac775be1034bf2d243f95e6f08" @@ -2659,6 +3049,18 @@ is-ci@^1.0.10: dependencies: ci-info "^1.0.0" +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + dependencies: + kind-of "^6.0.0" + is-date-object@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" @@ -2667,6 +3069,22 @@ is-decimal@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.1.tgz#f5fb6a94996ad9e8e3761fbfbd091f1fca8c4e82" +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + is-directory@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" @@ -2681,15 +3099,21 @@ is-equal-shallow@^0.1.3: dependencies: is-primitive "^2.0.0" -is-extendable@^0.1.1: +is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + dependencies: + is-plain-object "^2.0.4" + is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" -is-extglob@^2.1.0: +is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -2709,6 +3133,10 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" +is-generator-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -2721,6 +3149,12 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" +is-glob@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0" + dependencies: + is-extglob "^2.1.1" + is-hexadecimal@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz#6e084bbc92061fbb0971ec58b6ce6d404e24da69" @@ -2737,10 +3171,20 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" +is-odd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-2.0.0.tgz#7646624671fd7ea558ccd9a2795182f2958f1b24" + dependencies: + is-number "^4.0.0" + is-path-cwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" @@ -2761,6 +3205,12 @@ is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -2831,6 +3281,10 @@ is-whitespace-character@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.1.tgz#9ae0176f3282b65457a1992cdb084f8a5f833e3b" +is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + is-word-character@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.1.tgz#5a03fa1ea91ace8a6eb0c7cd770eb86d65c8befb" @@ -2849,6 +3303,10 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + isomorphic-fetch@^2.1.1, isomorphic-fetch@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9" @@ -2923,40 +3381,43 @@ istanbul-reports@^1.1.3: dependencies: handlebars "^4.0.3" -jest-changed-files@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-22.0.3.tgz#3771315acfa24a0ed7e6c545de620db6f1b2d164" +jest-changed-files@^22.2.0: + version "22.2.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-22.2.0.tgz#517610c4a8ca0925bdc88b0ca53bd678aa8d019e" dependencies: throat "^4.0.0" -jest-cli@^22.0.4: - version "22.0.4" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-22.0.4.tgz#0052abaad45c57861c05da8ab5d27bad13ad224d" +jest-cli@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-22.4.2.tgz#e6546dc651e13d164481aa3e76e53ac4f4edab06" dependencies: ansi-escapes "^3.0.0" chalk "^2.0.1" + exit "^0.1.2" glob "^7.1.2" graceful-fs "^4.1.11" + import-local "^1.0.0" is-ci "^1.0.10" istanbul-api "^1.1.14" istanbul-lib-coverage "^1.1.1" istanbul-lib-instrument "^1.8.0" istanbul-lib-source-maps "^1.2.1" - jest-changed-files "^22.0.3" - jest-config "^22.0.4" - jest-environment-jsdom "^22.0.4" - jest-get-type "^22.0.3" - jest-haste-map "^22.0.3" - jest-message-util "^22.0.3" - jest-regex-util "^22.0.3" - jest-resolve-dependencies "^22.0.3" - jest-runner "^22.0.4" - jest-runtime "^22.0.4" - jest-snapshot "^22.0.3" - jest-util "^22.0.4" - jest-worker "^22.0.3" + jest-changed-files "^22.2.0" + jest-config "^22.4.2" + jest-environment-jsdom "^22.4.1" + jest-get-type "^22.1.0" + jest-haste-map "^22.4.2" + jest-message-util "^22.4.0" + jest-regex-util "^22.1.0" + jest-resolve-dependencies "^22.1.0" + jest-runner "^22.4.2" + jest-runtime "^22.4.2" + jest-snapshot "^22.4.0" + jest-util "^22.4.1" + jest-validate "^22.4.2" + jest-worker "^22.2.2" micromatch "^2.3.11" - node-notifier "^5.1.2" + node-notifier "^5.2.1" realpath-native "^1.0.0" rimraf "^2.5.4" slash "^1.0.0" @@ -2965,100 +3426,101 @@ jest-cli@^22.0.4: which "^1.2.12" yargs "^10.0.3" -jest-config@^22.0.4: - version "22.0.4" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.0.4.tgz#9c2a46c0907b1a1af54d9cdbf18e99b447034e11" +jest-config@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-22.4.2.tgz#580ba5819bf81a5e48f4fd470e8b81834f45c855" dependencies: chalk "^2.0.1" glob "^7.1.1" - jest-environment-jsdom "^22.0.4" - jest-environment-node "^22.0.4" - jest-get-type "^22.0.3" - jest-jasmine2 "^22.0.4" - jest-regex-util "^22.0.3" - jest-resolve "^22.0.4" - jest-util "^22.0.4" - jest-validate "^22.0.3" - pretty-format "^22.0.3" - -jest-diff@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.0.3.tgz#ffed5aba6beaf63bb77819ba44dd520168986321" + jest-environment-jsdom "^22.4.1" + jest-environment-node "^22.4.1" + jest-get-type "^22.1.0" + jest-jasmine2 "^22.4.2" + jest-regex-util "^22.1.0" + jest-resolve "^22.4.2" + jest-util "^22.4.1" + jest-validate "^22.4.2" + pretty-format "^22.4.0" + +jest-diff@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-22.4.0.tgz#384c2b78519ca44ca126382df53f134289232525" dependencies: chalk "^2.0.1" diff "^3.2.0" - jest-get-type "^22.0.3" - pretty-format "^22.0.3" + jest-get-type "^22.1.0" + pretty-format "^22.4.0" -jest-docblock@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.0.3.tgz#c33aa22682b9fc68a5373f5f82994428a2ded601" +jest-docblock@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-22.4.0.tgz#dbf1877e2550070cfc4d9b07a55775a0483159b8" dependencies: detect-newline "^2.1.0" -jest-environment-jsdom@^22.0.4: - version "22.0.4" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-22.0.4.tgz#5723d4e724775ed38948de792e62f2d6a7f452df" +jest-environment-jsdom@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-22.4.1.tgz#754f408872441740100d3917e5ec40c74de6447f" dependencies: - jest-mock "^22.0.3" - jest-util "^22.0.4" + jest-mock "^22.2.0" + jest-util "^22.4.1" jsdom "^11.5.1" -jest-environment-node@^22.0.4: - version "22.0.4" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.0.4.tgz#068671f85a545f96a5469be3a3dd228fca79c709" +jest-environment-node@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-22.4.1.tgz#418850eb654596b8d6e36c2021cbedbc23df8e16" dependencies: - jest-mock "^22.0.3" - jest-util "^22.0.4" + jest-mock "^22.2.0" + jest-util "^22.4.1" -jest-get-type@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.0.3.tgz#fa894b677c0fcd55eff3fd8ee28c7be942e32d36" +jest-get-type@^22.1.0: + version "22.1.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.1.0.tgz#4e90af298ed6181edc85d2da500dbd2753e0d5a9" -jest-haste-map@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.0.3.tgz#c9ecb5c871c5465d4bde4139e527fa0dc784aa2d" +jest-haste-map@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-22.4.2.tgz#a90178e66146d4378bb076345a949071f3b015b4" dependencies: fb-watchman "^2.0.0" graceful-fs "^4.1.11" - jest-docblock "^22.0.3" - jest-worker "^22.0.3" + jest-docblock "^22.4.0" + jest-serializer "^22.4.0" + jest-worker "^22.2.2" micromatch "^2.3.11" sane "^2.0.0" -jest-jasmine2@^22.0.4: - version "22.0.4" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-22.0.4.tgz#f7c0965116efe831ec674dc954b0134639b3dcee" +jest-jasmine2@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-22.4.2.tgz#dfd3d259579ed6f52510d8f1ab692808f0d40691" dependencies: - callsites "^2.0.0" chalk "^2.0.1" - expect "^22.0.3" + co "^4.6.0" + expect "^22.4.0" graceful-fs "^4.1.11" - jest-diff "^22.0.3" - jest-matcher-utils "^22.0.3" - jest-message-util "^22.0.3" - jest-snapshot "^22.0.3" + is-generator-fn "^1.0.0" + jest-diff "^22.4.0" + jest-matcher-utils "^22.4.0" + jest-message-util "^22.4.0" + jest-snapshot "^22.4.0" + jest-util "^22.4.1" source-map-support "^0.5.0" -jest-leak-detector@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-22.0.3.tgz#b64904f0e8954a11edb79b0809ff4717fa762d99" +jest-leak-detector@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-22.4.0.tgz#64da77f05b001c96d2062226e079f89989c4aa2f" dependencies: - pretty-format "^22.0.3" - optionalDependencies: - weak "^1.0.1" + pretty-format "^22.4.0" -jest-matcher-utils@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.0.3.tgz#2ec15ca1af7dcabf4daddc894ccce224b948674e" +jest-matcher-utils@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-22.4.0.tgz#d55f5faf2270462736bdf7c7485ee931c9d4b6a1" dependencies: chalk "^2.0.1" - jest-get-type "^22.0.3" - pretty-format "^22.0.3" + jest-get-type "^22.1.0" + pretty-format "^22.4.0" -jest-message-util@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.0.3.tgz#bf674b2762ef2dd53facf2136423fcca264976df" +jest-message-util@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-22.4.0.tgz#e3d861df16d2fee60cb2bc8feac2188a42579642" dependencies: "@babel/code-frame" "^7.0.0-beta.35" chalk "^2.0.1" @@ -3066,57 +3528,60 @@ jest-message-util@^22.0.3: slash "^1.0.0" stack-utils "^1.0.1" -jest-mock@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-22.0.3.tgz#c875e47b5b729c6c020a2fab317b275c0cf88961" +jest-mock@^22.2.0: + version "22.2.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-22.2.0.tgz#444b3f9488a7473adae09bc8a77294afded397a7" -jest-regex-util@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-22.0.3.tgz#c5c10229de5ce2b27bf4347916d95b802ae9aa4d" +jest-regex-util@^22.1.0: + version "22.1.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-22.1.0.tgz#5daf2fe270074b6da63e5d85f1c9acc866768f53" -jest-resolve-dependencies@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-22.0.3.tgz#202ddf370069702cd1865a1952fcc7e52c92720e" +jest-resolve-dependencies@^22.1.0: + version "22.1.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-22.1.0.tgz#340e4139fb13315cd43abc054e6c06136be51e31" dependencies: - jest-regex-util "^22.0.3" + jest-regex-util "^22.1.0" -jest-resolve@^22.0.4: - version "22.0.4" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-22.0.4.tgz#a6e47f55e9388c7341b5e9732aedc6fe30906121" +jest-resolve@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-22.4.2.tgz#25d88aa4147462c9c1c6a1ba16250d3794c24d00" dependencies: browser-resolve "^1.11.2" chalk "^2.0.1" -jest-runner@^22.0.4: - version "22.0.4" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-22.0.4.tgz#3aa43a31b05ce8271539df580c2eb916023d3367" - dependencies: - jest-config "^22.0.4" - jest-docblock "^22.0.3" - jest-haste-map "^22.0.3" - jest-jasmine2 "^22.0.4" - jest-leak-detector "^22.0.3" - jest-message-util "^22.0.3" - jest-runtime "^22.0.4" - jest-util "^22.0.4" - jest-worker "^22.0.3" +jest-runner@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-22.4.2.tgz#19390ea9d99f768973e16f95a1efa351c0017e87" + dependencies: + exit "^0.1.2" + jest-config "^22.4.2" + jest-docblock "^22.4.0" + jest-haste-map "^22.4.2" + jest-jasmine2 "^22.4.2" + jest-leak-detector "^22.4.0" + jest-message-util "^22.4.0" + jest-runtime "^22.4.2" + jest-util "^22.4.1" + jest-worker "^22.2.2" throat "^4.0.0" -jest-runtime@^22.0.4: - version "22.0.4" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-22.0.4.tgz#8f69aa7b5fbb3acd35dc262cbf654e563f69b7b4" +jest-runtime@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-22.4.2.tgz#0de0444f65ce15ee4f2e0055133fc7c17b9168f3" dependencies: babel-core "^6.0.0" - babel-jest "^22.0.4" + babel-jest "^22.4.1" babel-plugin-istanbul "^4.1.5" chalk "^2.0.1" convert-source-map "^1.4.0" + exit "^0.1.2" graceful-fs "^4.1.11" - jest-config "^22.0.4" - jest-haste-map "^22.0.3" - jest-regex-util "^22.0.3" - jest-resolve "^22.0.4" - jest-util "^22.0.4" + jest-config "^22.4.2" + jest-haste-map "^22.4.2" + jest-regex-util "^22.1.0" + jest-resolve "^22.4.2" + jest-util "^22.4.1" + jest-validate "^22.4.2" json-stable-stringify "^1.0.1" micromatch "^2.3.11" realpath-native "^1.0.0" @@ -3125,54 +3590,64 @@ jest-runtime@^22.0.4: write-file-atomic "^2.1.0" yargs "^10.0.3" -jest-snapshot@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-22.0.3.tgz#a949b393781d2fdb4773f6ea765dd67ad1da291e" +jest-serializer@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-22.4.0.tgz#b5d145b98c4b0d2c20ab686609adbb81fe23b566" + +jest-snapshot@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-22.4.0.tgz#03d3ce63f8fa7352388afc6a3c8b5ccc3a180ed7" dependencies: chalk "^2.0.1" - jest-diff "^22.0.3" - jest-matcher-utils "^22.0.3" + jest-diff "^22.4.0" + jest-matcher-utils "^22.4.0" mkdirp "^0.5.1" natural-compare "^1.4.0" - pretty-format "^22.0.3" + pretty-format "^22.4.0" -jest-util@^22.0.4: - version "22.0.4" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.0.4.tgz#d920a513e0645aaab030cee38e4fe7d5bed8bb6d" +jest-util@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-22.4.1.tgz#dd17c3bdb067f8e90591563ec0c42bf847dc249f" dependencies: callsites "^2.0.0" chalk "^2.0.1" graceful-fs "^4.1.11" is-ci "^1.0.10" - jest-message-util "^22.0.3" - jest-validate "^22.0.3" + jest-message-util "^22.4.0" mkdirp "^0.5.1" + source-map "^0.6.0" -jest-validate@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-22.0.3.tgz#2850d949a36c48b1a40f7eebae1d8539126f7829" +jest-validate@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-22.4.2.tgz#e789a4e056173bf97fe797a2df2d52105c57d4f4" dependencies: chalk "^2.0.1" - jest-get-type "^22.0.3" + jest-config "^22.4.2" + jest-get-type "^22.1.0" leven "^2.1.0" - pretty-format "^22.0.3" + pretty-format "^22.4.0" -jest-worker@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.0.3.tgz#30433faca67814a8f80559f75ab2ceaa61332fd2" +jest-worker@^22.2.2: + version "22.2.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-22.2.2.tgz#c1f5dc39976884b81f68ec50cb8532b2cbab3390" dependencies: merge-stream "^1.0.1" -jest@^22.0.0: - version "22.0.4" - resolved "https://registry.yarnpkg.com/jest/-/jest-22.0.4.tgz#d3cf560ece6b825b115dce80b9826ceb40f87961" +jest@^22.4.2: + version "22.4.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-22.4.2.tgz#34012834a49bf1bdd3bc783850ab44e4499afc20" dependencies: - jest-cli "^22.0.4" + import-local "^1.0.0" + jest-cli "^22.4.2" js-base64@^2.1.9: version "2.3.2" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.3.2.tgz#a79a923666372b580f8e27f51845c6f7e8fbfbaf" +js-sha3@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.7.0.tgz#0a5c57b36f79882573b2d84051f8bb85dd1bd63a" + 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" @@ -3227,10 +3702,18 @@ jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" +jsesc@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" +json-parse-better-errors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz#50183cd1b2d25275de069e9e71b467ac9eab973a" + json-schema-traverse@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" @@ -3257,12 +3740,6 @@ json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" -jsonfile@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" - optionalDependencies: - graceful-fs "^4.1.6" - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -3286,7 +3763,7 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -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: @@ -3298,7 +3775,7 @@ kefir@^3.7.3: dependencies: symbol-observable "1.0.4" -kind-of@^3.0.2: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" dependencies: @@ -3310,14 +3787,28 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -known-css-properties@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.4.1.tgz#baaaf704e5f8a5f10e0e221212aae3ea738ea372" +kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" + +known-css-properties@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.6.1.tgz#31b5123ad03d8d1a3f36bd4155459c981173478b" lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" +lazy-cache@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-2.0.2.tgz#b9190a4f913354694840859f8a8f7084d8822264" + dependencies: + set-getter "^0.1.0" + lcid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" @@ -3420,6 +3911,15 @@ load-json-file@^3.0.0: pify "^2.0.0" strip-bom "^3.0.0" +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -3431,10 +3931,6 @@ lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" -lodash.cond@^4.3.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" - lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" @@ -3524,10 +4020,24 @@ makeshift@^1.1.0: sywac "^1.0.0" url-parse-as-address "^1.0.0" +map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + map-obj@^1.0.0, map-obj@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" +map-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + dependencies: + object-visit "^1.0.0" + markdown-escapes@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.1.tgz#1994df2d3af4811de59a6714934c2b2292734518" @@ -3582,6 +4092,20 @@ meow@^3.3.0, meow@^3.7.0: redent "^1.0.0" trim-newlines "^1.0.0" +meow@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-4.0.0.tgz#fd5855dd008db5b92c552082db1c307cba20b29d" + dependencies: + camelcase-keys "^4.0.0" + decamelize-keys "^1.0.0" + loud-rejection "^1.0.0" + minimist "^1.1.3" + minimist-options "^3.0.1" + normalize-package-data "^2.3.4" + read-pkg-up "^3.0.0" + redent "^2.0.0" + trim-newlines "^2.0.0" + merge-stream@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" @@ -3610,6 +4134,24 @@ micromatch@^2.1.5, micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" +micromatch@^3.1.4: + version "3.1.9" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.9.tgz#15dc93175ae39e52e93087847096effc73efcf89" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + mime-db@~1.30.0: version "1.30.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01" @@ -3630,6 +4172,13 @@ minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: dependencies: brace-expansion "^1.1.7" +minimist-options@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" + dependencies: + arrify "^1.0.1" + is-plain-obj "^1.1.0" + minimist@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" @@ -3650,6 +4199,13 @@ minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" +mixin-deep@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + "mkdirp@>=0.5 0", 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" @@ -3676,10 +4232,27 @@ 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.0.5, nan@^2.0.7, nan@^2.3.0, nan@^2.3.3: +nan@^2.0.7, nan@^2.3.0, nan@^2.3.3: version "2.8.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" +nanomatch@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.9.tgz#879f7150cb2dab7a471259066c104eee6e0fa7c2" + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-odd "^2.0.0" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -3709,14 +4282,14 @@ node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" -node-notifier@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff" +node-notifier@^5.2.1: + 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.39: version "0.6.39" @@ -3750,7 +4323,7 @@ normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package- semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.0, normalize-path@^2.0.1: +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: @@ -3799,10 +4372,24 @@ 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-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + dependencies: + isobject "^3.0.0" + object.getownpropertydescriptors@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" @@ -3817,6 +4404,12 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" +object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + dependencies: + isobject "^3.0.1" + once@^1.3.0, once@^1.3.3, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -3937,12 +4530,23 @@ parse-json@^3.0.0: dependencies: error-ex "^1.3.1" +parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + parse5@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" dependencies: "@types/node" "*" +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -4025,6 +4629,12 @@ pkg-dir@^1.0.0: dependencies: find-up "^1.0.0" +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + dependencies: + find-up "^2.1.0" + pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" @@ -4033,9 +4643,13 @@ pn@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/pn/-/pn-1.0.0.tgz#1cf5a30b0d806cd18f88fc41a6b5d4ad615b3ba9" -postcss-html@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.11.0.tgz#03a3ff3116f8a0fe0d46316ea21893d4db4b63af" +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + +postcss-html@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.12.0.tgz#39b6adb4005dfc5464df7999c0f81c95bced7e50" dependencies: htmlparser2 "^3.9.2" remark "^8.0.0" @@ -4104,7 +4718,7 @@ postcss@^5.2.16: source-map "^0.5.6" supports-color "^3.2.3" -postcss@^6.0.13, postcss@^6.0.14, postcss@^6.0.3, postcss@^6.0.6, postcss@^6.0.8: +postcss@^6.0.14, postcss@^6.0.3, postcss@^6.0.6, postcss@^6.0.8: version "6.0.14" resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.14.tgz#5534c72114739e75d0afcf017db853099f562885" dependencies: @@ -4120,6 +4734,14 @@ postcss@^6.0.16: source-map "^0.6.1" supports-color "^5.1.0" +postcss@^6.0.17, postcss@^6.0.19: + version "6.0.19" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.19.tgz#76a78386f670b9d9494a655bf23ac012effd1555" + dependencies: + chalk "^2.3.1" + source-map "^0.6.1" + supports-color "^5.2.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -4132,9 +4754,9 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -pretty-format@^22.0.3: - version "22.0.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.0.3.tgz#a2bfa59fc33ad24aa4429981bb52524b41ba5dd7" +pretty-format@^22.4.0: + version "22.4.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-22.4.0.tgz#237b1f7e1c50ed03bc65c03ccc29d7c8bb7beb94" dependencies: ansi-regex "^3.0.0" ansi-styles "^3.2.0" @@ -4193,6 +4815,10 @@ qs@~6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" +quick-lru@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" + randomatic@^1.1.3: version "1.1.7" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" @@ -4229,6 +4855,13 @@ read-pkg-up@^2.0.0: find-up "^2.0.0" read-pkg "^2.0.0" +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + dependencies: + find-up "^2.0.0" + read-pkg "^3.0.0" + read-pkg@^1.0.0, read-pkg@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" @@ -4245,6 +4878,14 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2: version "2.3.3" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" @@ -4279,6 +4920,13 @@ redent@^1.0.0: indent-string "^2.1.0" strip-indent "^1.0.1" +redent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" + dependencies: + indent-string "^3.0.0" + strip-indent "^2.0.0" + regenerate@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" @@ -4305,6 +4953,13 @@ regex-cache@^0.4.2: dependencies: is-equal-shallow "^0.1.3" +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + regexpu-core@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" @@ -4391,7 +5046,7 @@ repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" -repeat-string@^1.5.2, repeat-string@^1.5.4: +repeat-string@^1.5.2, repeat-string@^1.5.4, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" @@ -4492,14 +5147,28 @@ require-uncached@^1.0.3: caller-path "^0.1.0" resolve-from "^1.0.0" +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + dependencies: + resolve-from "^3.0.0" + resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" @@ -4517,6 +5186,10 @@ restore-cursor@^2.0.0: onetime "^2.0.0" signal-exit "^3.0.2" +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" @@ -4549,6 +5222,12 @@ 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" +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + dependencies: + ret "~0.1.10" + sane@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/sane/-/sane-2.2.0.tgz#d6d2e2fcab00e3d283c93b912b7c3a20846f1d56" @@ -4571,18 +5250,38 @@ sax@^1.2.1: version "5.4.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" -semver@5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" +set-getter@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/set-getter/-/set-getter-0.1.0.tgz#d769c182c9d5a51f409145f2fba82e5e86e80376" + dependencies: + to-object-path "^0.3.0" + 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" +set-value@^0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-0.4.3.tgz#7db08f9d3d22dc7f78e53af3c3bf4666ecdfccf1" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.1" + to-object-path "^0.3.0" + +set-value@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.0.tgz#71ae4a88f0feefbbf52d1ea604f3fb315ebb6274" + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -4597,7 +5296,7 @@ shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" -shellwords@^0.1.0: +shellwords@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" @@ -4615,6 +5314,33 @@ slice-ansi@1.0.0: dependencies: is-fullwidth-code-point "^2.0.0" +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.1.tgz#e12b5487faded3e3dea0ac91e9400bf75b401370" + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^2.0.0" + sntp@1.x.x: version "1.0.9" resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" @@ -4633,6 +5359,16 @@ sort-keys@^2.0.0: dependencies: is-plain-obj "^1.0.0" +source-map-resolve@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.1.tgz#7ad0f593f2281598e854df80f19aae4b92d7a11a" + dependencies: + atob "^2.0.0" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + source-map-support@^0.4.15: version "0.4.18" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" @@ -4645,13 +5381,17 @@ source-map-support@^0.5.0: dependencies: source-map "^0.6.0" +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" -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.1, source-map@~0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -4677,6 +5417,12 @@ specificity@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.3.2.tgz#99e6511eceef0f8d9b57924937aac2cb13d13c42" +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + dependencies: + extend-shallow "^3.0.0" + split2@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/split2/-/split2-2.2.0.tgz#186b2575bcf83e85b7d18465756238ee4ee42493" @@ -4715,6 +5461,13 @@ state-toggle@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.0.tgz#d20f9a616bb4f0c3b98b91922d25b640aa2bc425" +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + stealthy-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" @@ -4792,6 +5545,10 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" +strip-indent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -4810,24 +5567,24 @@ style-search@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" -stylelint-config-recommended@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-2.0.0.tgz#560a028e81ea3ca8894b9a8eef4c0e05ac60e090" +stylelint-config-recommended@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-2.1.0.tgz#f526d5c771c6811186d9eaedbed02195fee30858" -stylelint-config-standard@^18.0.0: - version "18.0.0" - resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-18.0.0.tgz#0d872b40fafdcddcf4188fb5b64ddb3887e8aefc" +stylelint-config-standard@^18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-18.2.0.tgz#6283149aba7f64f18731aef8f0abfb35cf619e06" dependencies: - stylelint-config-recommended "^2.0.0" + stylelint-config-recommended "^2.1.0" -stylelint@^8.2.0: - version "8.3.1" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-8.3.1.tgz#424c822f32c88e85025b55d72c7b98355e3fa6de" +stylelint@^9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.1.1.tgz#bfabb7eb8ea6251a4732f4b2a0468963a30d3da9" dependencies: - autoprefixer "^7.1.2" + autoprefixer "^8.0.0" balanced-match "^1.0.0" chalk "^2.0.1" - cosmiconfig "^3.1.0" + cosmiconfig "^4.0.0" debug "^3.0.0" execall "^1.0.0" file-entry-cache "^2.0.0" @@ -4837,25 +5594,27 @@ stylelint@^8.2.0: html-tags "^2.0.0" ignore "^3.3.3" imurmurhash "^0.1.4" - known-css-properties "^0.4.0" + known-css-properties "^0.6.0" lodash "^4.17.4" log-symbols "^2.0.0" mathml-tag-names "^2.0.1" - meow "^3.7.0" + meow "^4.0.0" micromatch "^2.3.11" normalize-selector "^0.2.0" pify "^3.0.0" - postcss "^6.0.6" - postcss-html "^0.11.0" + postcss "^6.0.16" + postcss-html "^0.12.0" postcss-less "^1.1.0" postcss-media-query-parser "^0.2.3" postcss-reporter "^5.0.0" postcss-resolve-nested-selector "^0.1.1" postcss-safe-parser "^3.0.1" + postcss-sass "^0.3.0" postcss-scss "^1.0.2" postcss-selector-parser "^3.1.0" postcss-value-parser "^3.3.0" resolve-from "^4.0.0" + signal-exit "^3.0.2" specificity "^0.3.1" string-width "^2.1.0" style-search "^0.1.0" @@ -4891,6 +5650,12 @@ supports-color@^5.1.0: dependencies: has-flag "^2.0.0" +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 "^3.0.0" + svg-tags@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" @@ -4907,7 +5672,7 @@ sywac@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/sywac/-/sywac-1.2.0.tgz#b0a05c4e0f459918e8e42e0f55e1c1039a0e975c" -table@^4.0.1: +table@4.0.2, table@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/table/-/table-4.0.2.tgz#a33447375391e766ad34d3486e6e2aedc84d2e36" dependencies: @@ -5016,6 +5781,28 @@ 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" +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + tough-cookie@>=2.3.3, tough-cookie@^2.3.3, 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" @@ -5032,6 +5819,10 @@ trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" +trim-newlines@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" + trim-off-newlines@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" @@ -5066,6 +5857,10 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" +tweetnacl@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.0.tgz#713d8b818da42068740bf68386d0479e66fc8a7b" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -5134,6 +5929,15 @@ unified@^6.0.0: x-is-function "^1.0.4" x-is-string "^0.1.0" +union-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^0.4.3" + uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" @@ -5174,10 +5978,25 @@ universalify@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7" +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + unzip-response@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" +upath@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.0.4.tgz#ee2321ba0a786c50973db043a50b7bcba822361d" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + url-parse-as-address@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-as-address/-/url-parse-as-address-1.0.0.tgz#fb80901883f338b3cbed3538f5faa26adaf7f2e7" @@ -5188,6 +6007,14 @@ url-parse-lax@^1.0.0: dependencies: prepend-http "^1.0.1" +use@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/use/-/use-2.0.2.tgz#ae28a0d72f93bf22422a18a2e379993112dec8e8" + dependencies: + define-property "^0.2.5" + isobject "^3.0.0" + lazy-cache "^2.0.2" + user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" @@ -5270,13 +6097,6 @@ wcwidth@^1.0.0: dependencies: defaults "^1.0.3" -weak@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/weak/-/weak-1.0.1.tgz#ab99aab30706959aa0200cb8cf545bb9cb33b99e" - dependencies: - bindings "^1.2.1" - nan "^2.0.5" - webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -5312,7 +6132,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.2.12, which@^1.2.9: +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: @@ -5399,6 +6219,12 @@ xtend@^4.0.1, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" +xxhashjs@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/xxhashjs/-/xxhashjs-0.2.2.tgz#8a6251567621a1c46a5ae204da0249c7f8caa9d8" + dependencies: + cuint "^0.2.2" + y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" @@ -5423,6 +6249,12 @@ yargs-parser@^8.0.0: dependencies: camelcase "^4.1.0" +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + dependencies: + camelcase "^4.1.0" + yargs@^10.0.3: version "10.0.3" resolved "https://registry.yarnpkg.com/yargs/-/yargs-10.0.3.tgz#6542debd9080ad517ec5048fb454efe9e4d4aaae" @@ -5440,6 +6272,23 @@ yargs@^10.0.3: y18n "^3.2.1" yargs-parser "^8.0.0" +yargs@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.0.0.tgz#c052931006c5eee74610e5fc0354bedfd08a201b" + dependencies: + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^2.0.0" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^2.0.0" + which-module "^2.0.0" + y18n "^3.2.1" + yargs-parser "^9.0.2" + yargs@^8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" From 02f4bb24a59a4d561f379c0486f19c0d48f9dc75 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 15 Mar 2018 09:17:39 +0100 Subject: [PATCH 2/8] Functional JsonRpcCoder --- packages/api-provider/src/jsonRpcCoder.js | 52 ------------------- .../src/jsonRpcCoder/encodeJson.js | 14 +++++ .../src/jsonRpcCoder/encodeObject.js | 16 ++++++ .../api-provider/src/jsonRpcCoder/index.js | 26 ++++++++++ .../api-provider/src/jsonRpcCoder/types.js | 14 +++++ 5 files changed, 70 insertions(+), 52 deletions(-) delete mode 100644 packages/api-provider/src/jsonRpcCoder.js create mode 100644 packages/api-provider/src/jsonRpcCoder/encodeJson.js create mode 100644 packages/api-provider/src/jsonRpcCoder/encodeObject.js create mode 100644 packages/api-provider/src/jsonRpcCoder/index.js create mode 100644 packages/api-provider/src/jsonRpcCoder/types.js diff --git a/packages/api-provider/src/jsonRpcCoder.js b/packages/api-provider/src/jsonRpcCoder.js deleted file mode 100644 index 06c96c72a328..000000000000 --- a/packages/api-provider/src/jsonRpcCoder.js +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017-2018 Jaco Greeff -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. -// @flow - -import type { JsonRpcRequest, JsonRpcResponse } from './types'; - -const assert = require('@polkadot/util/assert'); -const isNumber = require('@polkadot/util/is/number'); -const isUndefined = require('@polkadot/util/is/undefined'); - -module.exports = class JsonRpcCoder { - _id: number = 0; - - decodeResponse (response: JsonRpcResponse): mixed { - assert(response, 'Empty response object received'); - - assert(response.jsonrpc === '2.0', 'Invalid jsonrpc field in decoded object'); - - assert(isNumber(response.id), 'Invalid id field in decoded object'); - - if (response.error) { - const { code, message } = response.error; - - throw new Error(`[${code}]: ${message}`); - } - - assert(!isUndefined(response.result), 'No result found in JsonRpc response'); - - return response.result; - } - - encodeObject (method: string, params: Array): JsonRpcRequest { - return { - id: ++this._id, - jsonrpc: '2.0', - method, - params - }; - } - - encodeJson (method: string, params: Array): string { - return JSON.stringify( - this.encodeObject(method, params) - ); - } - - // flowlint-next-line unsafe-getters-setters:off - get id (): number { - return this._id; - } -}; diff --git a/packages/api-provider/src/jsonRpcCoder/encodeJson.js b/packages/api-provider/src/jsonRpcCoder/encodeJson.js new file mode 100644 index 000000000000..30e67e5d85d1 --- /dev/null +++ b/packages/api-provider/src/jsonRpcCoder/encodeJson.js @@ -0,0 +1,14 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { RpcCoderState } from './types'; + +const encodeObject = require('./encodeObject'); + +module.exports = function encodeJson (self: RpcCoderState, method: string, params: Array): string { + return JSON.stringify( + encodeObject(self, method, params) + ); +}; diff --git a/packages/api-provider/src/jsonRpcCoder/encodeObject.js b/packages/api-provider/src/jsonRpcCoder/encodeObject.js new file mode 100644 index 000000000000..5a205b15b943 --- /dev/null +++ b/packages/api-provider/src/jsonRpcCoder/encodeObject.js @@ -0,0 +1,16 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { JsonRpcRequest } from '../types'; +import type { RpcCoderState } from './types'; + +module.exports = function encodeObject (self: RpcCoderState, method: string, params: Array): JsonRpcRequest { + return { + id: ++self.id, + jsonrpc: '2.0', + method, + params + }; +}; diff --git a/packages/api-provider/src/jsonRpcCoder/index.js b/packages/api-provider/src/jsonRpcCoder/index.js new file mode 100644 index 000000000000..f207791685af --- /dev/null +++ b/packages/api-provider/src/jsonRpcCoder/index.js @@ -0,0 +1,26 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { JsonRpcRequest, JsonRpcResponse } from '../types'; +import type { RpcCoder, RpcCoderState } from './types'; + +const decodeResponse = require('./decodeResponse'); +const encodeJson = require('./encodeJson'); +const encodeObject = require('./encodeObject'); + +module.exports = function rpcCoder (): RpcCoder { + const self: RpcCoderState = { + id: 0 + }; + + return { + decodeResponse: (response: JsonRpcResponse): mixed => + decodeResponse(self, response), + encodeJson: (method: string, params: Array): string => + encodeJson(self, method, params), + encodeObject: (method: string, params: Array): JsonRpcRequest => + encodeObject(self, method, params) + }; +}; diff --git a/packages/api-provider/src/jsonRpcCoder/types.js b/packages/api-provider/src/jsonRpcCoder/types.js new file mode 100644 index 000000000000..d0f203839433 --- /dev/null +++ b/packages/api-provider/src/jsonRpcCoder/types.js @@ -0,0 +1,14 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +export type RpcCoder = { + decodeResponse: (response: JsonRpcResponse) => mixed, + encodeObject: (method: string, params: Array) => JsonRpcRequest, + encodeJson: (method: string, params: Array) => string +}; + +export type RpcCoderState = { + id: number +}; From 2806e4e20890a02a308dc5ff315cae08a6292337 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 15 Mar 2018 09:17:56 +0100 Subject: [PATCH 3/8] Functional HttpProvider --- packages/api-provider/src/http/index.js | 61 ++++++++----------- packages/api-provider/src/http/index.spec.js | 6 +- packages/api-provider/src/http/send.js | 27 ++++++++ packages/api-provider/src/http/subscribe.js | 10 +++ packages/api-provider/src/http/types.js | 11 ++++ packages/api-provider/src/http/unsubscribe.js | 10 +++ packages/api-provider/src/index.js | 8 +-- .../src/jsonRpcCoder/decodeResponse.js | 29 +++++++++ packages/api-provider/src/types.js | 9 +-- packages/api-provider/src/ws/index.js | 4 +- 10 files changed, 124 insertions(+), 51 deletions(-) create mode 100644 packages/api-provider/src/http/send.js create mode 100644 packages/api-provider/src/http/subscribe.js create mode 100644 packages/api-provider/src/http/types.js create mode 100644 packages/api-provider/src/http/unsubscribe.js create mode 100644 packages/api-provider/src/jsonRpcCoder/decodeResponse.js diff --git a/packages/api-provider/src/http/index.js b/packages/api-provider/src/http/index.js index 5ccb322c001d..dc6565346728 100644 --- a/packages/api-provider/src/http/index.js +++ b/packages/api-provider/src/http/index.js @@ -3,45 +3,34 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { ProviderInterface } from '../types'; +import type { ProviderInterface, ProviderInterface$Callback } from '../types'; +import type { HttpState } from './types'; require('./polyfill'); const assert = require('@polkadot/util/assert'); -const JsonRpcCoder = require('../jsonRpcCoder'); -module.exports = class HttpProvider extends JsonRpcCoder implements ProviderInterface { - _endpoint: string; - - constructor (endpoint: string) { - super(); - - assert(/^http:\/\//.test(endpoint), `Endpoint should start with 'http://', received '${endpoint}'`); - - this._endpoint = endpoint; - } - - // flowlint-next-line unsafe-getters-setters:off - get isConnected (): boolean { - return true; - } - - async send (method: string, params: Array): Promise { - const body = this.encodeJson(method, params); - const response = await fetch(this._endpoint, { - body, - headers: { - 'Accept': 'application/json', - 'Content-Length': `${body.length}`, - 'Content-Type': 'application/json' - }, - method: 'POST' - }); - - assert(response.ok, `[${response.status}]: ${response.statusText}`); - - const result = await response.json(); - - return this.decodeResponse(result); - } +const coder = require('../jsonRpcCoder'); +const send = require('./send'); +const subscribe = require('./subscribe'); +const unsubscribe = require('./unsubscribe'); + +module.exports = function httpProvider (endpoint: string): ProviderInterface { + const self: HttpState = { + coder: coder(), + endpoint + }; + + assert(/^http:\/\//.test(endpoint), `Endpoint should start with 'http://', received '${endpoint}'`); + + return { + isConnected: (): boolean => + true, + send: (method: string, params: Array): Promise => + send(self, method, params), + subscribe: (method: string, params: Array, cb: ProviderInterface$Callback): Promise => + subscribe(self, method, params, cb), + unsubscribe: (id: number): Promise => + unsubscribe(self, id) + }; }; diff --git a/packages/api-provider/src/http/index.spec.js b/packages/api-provider/src/http/index.spec.js index 449d606507ec..182e6fb470bd 100644 --- a/packages/api-provider/src/http/index.spec.js +++ b/packages/api-provider/src/http/index.spec.js @@ -4,7 +4,7 @@ const { mockHttp, TEST_HTTP_URL } = require('../../test/mockHttp'); -const Http = require('./index'); +const createHttp = require('./index'); describe('Http', () => { let http; @@ -13,7 +13,7 @@ describe('Http', () => { let decodeSpy; beforeEach(() => { - http = new Http(TEST_HTTP_URL); + http = createHttp(TEST_HTTP_URL); encodeSpy = jest.spyOn(http, 'encodeJson'); decodeSpy = jest.spyOn(http, 'decodeResponse'); @@ -31,7 +31,7 @@ describe('Http', () => { it('requires an http:// prefixed endpoint', () => { expect( - () => new Http('ws://') + () => createHttp('ws://') ).toThrow(/with 'http/); }); diff --git a/packages/api-provider/src/http/send.js b/packages/api-provider/src/http/send.js new file mode 100644 index 000000000000..78d8dc38e4ef --- /dev/null +++ b/packages/api-provider/src/http/send.js @@ -0,0 +1,27 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { HttpState } from './types'; + +const assert = require('@polkadot/util/assert'); + +module.exports = async function send ({ coder, endpoint }: HttpState, method: string, params: Array): Promise { + const body = coder.encodeJson(method, params); + const response = await fetch(endpoint, { + body, + headers: { + 'Accept': 'application/json', + 'Content-Length': `${body.length}`, + 'Content-Type': 'application/json' + }, + method: 'POST' + }); + + assert(response.ok, `[${response.status}]: ${response.statusText}`); + + const result = await response.json(); + + return coder.decodeResponse(result); +}; diff --git a/packages/api-provider/src/http/subscribe.js b/packages/api-provider/src/http/subscribe.js new file mode 100644 index 000000000000..ded773c3f4a6 --- /dev/null +++ b/packages/api-provider/src/http/subscribe.js @@ -0,0 +1,10 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { HttpState } from './types'; + +module.exports = async function subscribe (self: HttpState, method: string, params: Array, cb: ProviderInterface$Callback): Promise { + throw new Error('Subscriptions has not been implemented'); +}; diff --git a/packages/api-provider/src/http/types.js b/packages/api-provider/src/http/types.js new file mode 100644 index 000000000000..80841d7c8274 --- /dev/null +++ b/packages/api-provider/src/http/types.js @@ -0,0 +1,11 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { RpcCoder } from '../jsonRpcCoder'; + +export type HttpState = { + coder: RpcCoder, + endpoint: string +}; diff --git a/packages/api-provider/src/http/unsubscribe.js b/packages/api-provider/src/http/unsubscribe.js new file mode 100644 index 000000000000..e933ffda6e66 --- /dev/null +++ b/packages/api-provider/src/http/unsubscribe.js @@ -0,0 +1,10 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { HttpState } from './types'; + +module.exports = async function unsubscribe (self: HttpState, id: number): Promise { + throw new Error('Subscriptions has not been implemented'); +}; diff --git a/packages/api-provider/src/index.js b/packages/api-provider/src/index.js index da9abc9f86de..eb7f494c342c 100644 --- a/packages/api-provider/src/index.js +++ b/packages/api-provider/src/index.js @@ -3,10 +3,10 @@ // of the ISC license. See the LICENSE file for details. // @flow -const Http = require('./http'); -const Ws = require('./ws'); +const http = require('./http'); +const ws = require('./ws'); module.exports = { - Http, - Ws + http, + ws }; diff --git a/packages/api-provider/src/jsonRpcCoder/decodeResponse.js b/packages/api-provider/src/jsonRpcCoder/decodeResponse.js new file mode 100644 index 000000000000..39154bea48da --- /dev/null +++ b/packages/api-provider/src/jsonRpcCoder/decodeResponse.js @@ -0,0 +1,29 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { JsonRpcResponse } from '../types'; +import type { RpcCoderState } from './types'; + +const assert = require('@polkadot/util/assert'); +const isNumber = require('@polkadot/util/is/number'); +const isUndefined = require('@polkadot/util/is/undefined'); + +module.exports = function decodeResponse (self: RpcCoderState, response: JsonRpcResponse): mixed { + assert(response, 'Empty response object received'); + + assert(response.jsonrpc === '2.0', 'Invalid jsonrpc field in decoded object'); + + assert(isNumber(response.id), 'Invalid id field in decoded object'); + + if (response.error) { + const { code, message } = response.error; + + throw new Error(`[${code}]: ${message}`); + } + + assert(!isUndefined(response.result), 'No result found in JsonRpc response'); + + return response.result; +}; diff --git a/packages/api-provider/src/types.js b/packages/api-provider/src/types.js index 44895eca60f8..576b4cfc3be1 100644 --- a/packages/api-provider/src/types.js +++ b/packages/api-provider/src/types.js @@ -23,15 +23,12 @@ export type JsonRpcResponseBase = { export type JsonRpcResponse = JsonRpcObject & JsonRpcResponseBase; +export type ProviderInterface$Callback = (error: ?Error, result: mixed) => void; + export interface ProviderInterface { +isConnected: boolean; send (method: string, params: Array): Promise; -} - -export type ProviderInterface$Subscribe$Callback = (error: ?Error, result: mixed) => void; - -export interface ProviderInterface$Subscribe extends ProviderInterface { - subscribe (method: string, params: Array, cb: ProviderInterface$Subscribe$Callback): Promise; + subscribe (method: string, params: Array, cb: ProviderInterface$Callback): Promise; unsubscribe (id: number): Promise; } diff --git a/packages/api-provider/src/ws/index.js b/packages/api-provider/src/ws/index.js index 6f8e3a63ec50..114d4236875b 100644 --- a/packages/api-provider/src/ws/index.js +++ b/packages/api-provider/src/ws/index.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { JsonRpcResponse, ProviderInterface$Subscribe, ProviderInterface$Subscribe$Callback } from '../types'; +import type { JsonRpcResponse, ProviderInterface$Callback } from '../types'; type Awaiting = { callback: (error: ?Error, result: mixed) => void @@ -131,7 +131,7 @@ module.exports = class WsProvider extends JsonRpcCoder implements ProviderInterf }); } - subscribe (method: string, params: Array, cb: ProviderInterface$Subscribe$Callback): Promise { + subscribe (method: string, params: Array, cb: ProviderInterface$Callback): Promise { throw new Error('Subscriptions has not been implemented'); } From b6e175d3bd1fd286e04c842f851626f8f05e22b2 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 15 Mar 2018 10:18:59 +0100 Subject: [PATCH 4/8] Functional WsProvider --- packages/api-provider/src/http/index.js | 12 +- packages/api-provider/src/http/index.spec.js | 99 +---------- packages/api-provider/src/http/send.spec.js | 98 +++++++++++ packages/api-provider/src/http/state.js | 21 +++ packages/api-provider/src/http/state.spec.js | 13 ++ packages/api-provider/src/http/types.js | 4 +- .../api-provider/src/jsonRpcCoder.spec.js | 79 --------- .../src/jsonRpcCoder/decodeResponse.spec.js | 49 ++++++ .../src/jsonRpcCoder/encodeJson.spec.js | 19 +++ .../src/jsonRpcCoder/encodeObject.spec.js | 29 ++++ .../api-provider/src/jsonRpcCoder/index.js | 4 +- packages/api-provider/src/types.js | 11 +- packages/api-provider/src/ws/connect.js | 20 +++ packages/api-provider/src/ws/index.js | 156 +++--------------- packages/api-provider/src/ws/index.spec.js | 10 +- packages/api-provider/src/ws/onClose.js | 20 +++ packages/api-provider/src/ws/onError.js | 12 ++ packages/api-provider/src/ws/onMessage.js | 29 ++++ packages/api-provider/src/ws/onOpen.js | 28 ++++ packages/api-provider/src/ws/send.js | 32 ++++ packages/api-provider/src/ws/state.js | 25 +++ packages/api-provider/src/ws/state.spec.js | 13 ++ packages/api-provider/src/ws/subscribe.js | 10 ++ packages/api-provider/src/ws/types.js | 21 +++ packages/api-provider/src/ws/unsubscribe.js | 10 ++ 25 files changed, 491 insertions(+), 333 deletions(-) create mode 100644 packages/api-provider/src/http/send.spec.js create mode 100644 packages/api-provider/src/http/state.js create mode 100644 packages/api-provider/src/http/state.spec.js delete mode 100644 packages/api-provider/src/jsonRpcCoder.spec.js create mode 100644 packages/api-provider/src/jsonRpcCoder/decodeResponse.spec.js create mode 100644 packages/api-provider/src/jsonRpcCoder/encodeJson.spec.js create mode 100644 packages/api-provider/src/jsonRpcCoder/encodeObject.spec.js create mode 100644 packages/api-provider/src/ws/connect.js create mode 100644 packages/api-provider/src/ws/onClose.js create mode 100644 packages/api-provider/src/ws/onError.js create mode 100644 packages/api-provider/src/ws/onMessage.js create mode 100644 packages/api-provider/src/ws/onOpen.js create mode 100644 packages/api-provider/src/ws/send.js create mode 100644 packages/api-provider/src/ws/state.js create mode 100644 packages/api-provider/src/ws/state.spec.js create mode 100644 packages/api-provider/src/ws/subscribe.js create mode 100644 packages/api-provider/src/ws/types.js create mode 100644 packages/api-provider/src/ws/unsubscribe.js diff --git a/packages/api-provider/src/http/index.js b/packages/api-provider/src/http/index.js index dc6565346728..770c2fce5dc2 100644 --- a/packages/api-provider/src/http/index.js +++ b/packages/api-provider/src/http/index.js @@ -4,24 +4,16 @@ // @flow import type { ProviderInterface, ProviderInterface$Callback } from '../types'; -import type { HttpState } from './types'; require('./polyfill'); -const assert = require('@polkadot/util/assert'); - -const coder = require('../jsonRpcCoder'); const send = require('./send'); const subscribe = require('./subscribe'); +const state = require('./state'); const unsubscribe = require('./unsubscribe'); module.exports = function httpProvider (endpoint: string): ProviderInterface { - const self: HttpState = { - coder: coder(), - endpoint - }; - - assert(/^http:\/\//.test(endpoint), `Endpoint should start with 'http://', received '${endpoint}'`); + const self = state(endpoint); return { isConnected: (): boolean => diff --git a/packages/api-provider/src/http/index.spec.js b/packages/api-provider/src/http/index.spec.js index 182e6fb470bd..e5814d80e087 100644 --- a/packages/api-provider/src/http/index.spec.js +++ b/packages/api-provider/src/http/index.spec.js @@ -2,111 +2,18 @@ // This software may be modified and distributed under the terms // of the ISC license. See the LICENSE file for details. -const { mockHttp, TEST_HTTP_URL } = require('../../test/mockHttp'); +const { TEST_HTTP_URL } = require('../../test/mockHttp'); const createHttp = require('./index'); describe('Http', () => { let http; - let mock; - let encodeSpy; - let decodeSpy; beforeEach(() => { http = createHttp(TEST_HTTP_URL); - - encodeSpy = jest.spyOn(http, 'encodeJson'); - decodeSpy = jest.spyOn(http, 'decodeResponse'); - }); - - afterEach(() => { - encodeSpy.mockRestore(); - decodeSpy.mockRestore(); - - if (mock) { - mock.done(); - mock = null; - } - }); - - it('requires an http:// prefixed endpoint', () => { - expect( - () => createHttp('ws://') - ).toThrow(/with 'http/); - }); - - describe('isConnected', () => { - it('always returns true', () => { - expect(http.isConnected).toEqual(true); - }); }); - describe('send', () => { - it('encodes requests', () => { - mock = mockHttp([{ - method: 'test_encoding', - reply: { - result: 'ok' - } - }]); - - return http - .send('test_encoding', ['param']) - .then((result) => { - expect(encodeSpy).toHaveBeenCalledWith('test_encoding', ['param']); - }); - }); - - it('decodes responses', () => { - mock = mockHttp([{ - method: 'test_encoding', - reply: { - result: 'ok' - } - }]); - - return http - .send('test_encoding', ['param']) - .then((result) => { - expect(decodeSpy).toHaveBeenCalledWith({ - id: 1, - jsonrpc: '2.0', - result: 'ok' - }); - }); - }); - - it('passes the body through correctly', () => { - mock = mockHttp([{ - method: 'test_body', - reply: { - result: 'ok' - } - }]); - - return http - .send('test_body', ['param']) - .then((result) => { - expect(mock.body['test_body']).toEqual({ - id: 1, - jsonrpc: '2.0', - method: 'test_body', - params: ['param'] - }); - }); - }); - - it('throws error when !response.ok', () => { - mock = mockHttp([{ - code: 500, - method: 'test_error' - }]); - - return http - .send('test_error', []) - .catch((error) => { - expect(error.message).toMatch(/\[500\]: Internal Server/); - }); - }); + it('always returns isConnected true', () => { + expect(http.isConnected).toEqual(true); }); }); diff --git a/packages/api-provider/src/http/send.spec.js b/packages/api-provider/src/http/send.spec.js new file mode 100644 index 000000000000..fdd9659189e5 --- /dev/null +++ b/packages/api-provider/src/http/send.spec.js @@ -0,0 +1,98 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const { mockHttp, TEST_HTTP_URL } = require('../../test/mockHttp'); + +const createHttp = require('./index'); + +describe('send', () => { + let http; + let mock; + let encodeSpy; + let decodeSpy; + + beforeEach(() => { + http = createHttp(TEST_HTTP_URL); + + encodeSpy = jest.spyOn(http, 'encodeJson'); + decodeSpy = jest.spyOn(http, 'decodeResponse'); + }); + + afterEach(() => { + encodeSpy.mockRestore(); + decodeSpy.mockRestore(); + + if (mock) { + mock.done(); + mock = null; + } + }); + + it('encodes requests', () => { + mock = mockHttp([{ + method: 'test_encoding', + reply: { + result: 'ok' + } + }]); + + return http + .send('test_encoding', ['param']) + .then((result) => { + expect(encodeSpy).toHaveBeenCalledWith('test_encoding', ['param']); + }); + }); + + it('decodes responses', () => { + mock = mockHttp([{ + method: 'test_encoding', + reply: { + result: 'ok' + } + }]); + + return http + .send('test_encoding', ['param']) + .then((result) => { + expect(decodeSpy).toHaveBeenCalledWith({ + id: 1, + jsonrpc: '2.0', + result: 'ok' + }); + }); + }); + + it('passes the body through correctly', () => { + mock = mockHttp([{ + method: 'test_body', + reply: { + result: 'ok' + } + }]); + + return http + .send('test_body', ['param']) + .then((result) => { + expect(mock.body['test_body']).toEqual({ + id: 1, + jsonrpc: '2.0', + method: 'test_body', + params: ['param'] + }); + }); + }); + + it('throws error when !response.ok', () => { + mock = mockHttp([{ + code: 500, + method: 'test_error' + }]); + + return http + .send('test_error', []) + .catch((error) => { + expect(error.message).toMatch(/\[500\]: Internal Server/); + }); + }); +}); diff --git a/packages/api-provider/src/http/state.js b/packages/api-provider/src/http/state.js new file mode 100644 index 000000000000..4c3c8b2901f8 --- /dev/null +++ b/packages/api-provider/src/http/state.js @@ -0,0 +1,21 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { HttpState } from './types'; + +const assert = require('@polkadot/util/assert'); +const l = require('@polkadot/util/logger')('http-provider'); + +const coder = require('../jsonRpcCoder'); + +module.exports = function state (endpoint: string): HttpState { + assert(/^http:\/\//.test(endpoint), `Endpoint should start with 'http://', received '${endpoint}'`); + + return { + coder: coder(), + endpoint, + l + }; +}; diff --git a/packages/api-provider/src/http/state.spec.js b/packages/api-provider/src/http/state.spec.js new file mode 100644 index 000000000000..c9b201e62df2 --- /dev/null +++ b/packages/api-provider/src/http/state.spec.js @@ -0,0 +1,13 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const state = require('./state'); + +describe('state', () => { + it('requires an http:// prefixed endpoint', () => { + expect( + () => state('ws://') + ).toThrow(/with 'http/); + }); +}); diff --git a/packages/api-provider/src/http/types.js b/packages/api-provider/src/http/types.js index 80841d7c8274..f314ab348e7c 100644 --- a/packages/api-provider/src/http/types.js +++ b/packages/api-provider/src/http/types.js @@ -3,9 +3,11 @@ // of the ISC license. See the LICENSE file for details. // @flow +import type { Logger } from '@polkadot/util/types'; import type { RpcCoder } from '../jsonRpcCoder'; export type HttpState = { coder: RpcCoder, - endpoint: string + endpoint: string, + l: Logger }; diff --git a/packages/api-provider/src/jsonRpcCoder.spec.js b/packages/api-provider/src/jsonRpcCoder.spec.js deleted file mode 100644 index 6366c79ac191..000000000000 --- a/packages/api-provider/src/jsonRpcCoder.spec.js +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2017-2018 Jaco Greeff -// This software may be modified and distributed under the terms -// of the ISC license. See the LICENSE file for details. - -const JsonRpcCoder = require('./jsonRpcCoder'); - -describe('JsonRpcCoder', () => { - let coder; - - beforeEach(() => { - coder = new JsonRpcCoder(); - }); - - describe('id', () => { - it('starts with id === 0 (nothing sent)', () => { - expect(coder.id).toEqual(0); - }); - }); - - describe('decodeResponse', () => { - it('expects a non-empty input object', () => { - expect( - () => coder.decodeResponse() - ).toThrow(/Empty response/); - }); - - it('expects a valid jsonrpc field', () => { - expect( - () => coder.decodeResponse({}) - ).toThrow(/Invalid jsonrpc/); - }); - - it('expects a valid id field', () => { - expect( - () => coder.decodeResponse({ jsonrpc: '2.0' }) - ).toThrow(/Invalid id/); - }); - - it('expects a valid result field', () => { - expect( - () => coder.decodeResponse({ id: 1, jsonrpc: '2.0' }) - ).toThrow(/No result/); - }); - - it('throws any error found', () => { - expect( - () => coder.decodeResponse({ id: 1, jsonrpc: '2.0', error: { code: 123, message: 'test error' } }) - ).toThrow(/\[123\]: test error/); - }); - - it('returns the result', () => { - expect( - coder.decodeResponse({ id: 1, jsonrpc: '2.0', result: 'some result' }) - ).toEqual('some result'); - }); - }); - - describe('encodeObject', () => { - it('encodes a valid JsonRPC object', () => { - expect( - coder.encodeObject('method', 'params') - ).toEqual({ - id: 1, - jsonrpc: '2.0', - method: 'method', - params: 'params' - }); - expect(coder.id).toEqual(1); - }); - }); - - describe('encodeJson', () => { - it('encodes a valid JsonRPC JSON string', () => { - expect( - coder.encodeJson('method', 'params') - ).toEqual('{"id":1,"jsonrpc":"2.0","method":"method","params":"params"}'); - }); - }); -}); diff --git a/packages/api-provider/src/jsonRpcCoder/decodeResponse.spec.js b/packages/api-provider/src/jsonRpcCoder/decodeResponse.spec.js new file mode 100644 index 000000000000..e501d1bbd4a8 --- /dev/null +++ b/packages/api-provider/src/jsonRpcCoder/decodeResponse.spec.js @@ -0,0 +1,49 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const createCoder = require('./index'); + +describe('decodeResponse', () => { + let coder; + + beforeEach(() => { + coder = createCoder(); + }); + + it('expects a non-empty input object', () => { + expect( + () => coder.decodeResponse() + ).toThrow(/Empty response/); + }); + + it('expects a valid jsonrpc field', () => { + expect( + () => coder.decodeResponse({}) + ).toThrow(/Invalid jsonrpc/); + }); + + it('expects a valid id field', () => { + expect( + () => coder.decodeResponse({ jsonrpc: '2.0' }) + ).toThrow(/Invalid id/); + }); + + it('expects a valid result field', () => { + expect( + () => coder.decodeResponse({ id: 1, jsonrpc: '2.0' }) + ).toThrow(/No result/); + }); + + it('throws any error found', () => { + expect( + () => coder.decodeResponse({ id: 1, jsonrpc: '2.0', error: { code: 123, message: 'test error' } }) + ).toThrow(/\[123\]: test error/); + }); + + it('returns the result', () => { + expect( + coder.decodeResponse({ id: 1, jsonrpc: '2.0', result: 'some result' }) + ).toEqual('some result'); + }); +}); diff --git a/packages/api-provider/src/jsonRpcCoder/encodeJson.spec.js b/packages/api-provider/src/jsonRpcCoder/encodeJson.spec.js new file mode 100644 index 000000000000..1ddc82e8bf9b --- /dev/null +++ b/packages/api-provider/src/jsonRpcCoder/encodeJson.spec.js @@ -0,0 +1,19 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const createCoder = require('./index'); + +describe('encodeJson', () => { + let coder; + + beforeEach(() => { + coder = createCoder(); + }); + + it('encodes a valid JsonRPC JSON string', () => { + expect( + coder.encodeJson('method', 'params') + ).toEqual('{"id":1,"jsonrpc":"2.0","method":"method","params":"params"}'); + }); +}); diff --git a/packages/api-provider/src/jsonRpcCoder/encodeObject.spec.js b/packages/api-provider/src/jsonRpcCoder/encodeObject.spec.js new file mode 100644 index 000000000000..29f090bc796d --- /dev/null +++ b/packages/api-provider/src/jsonRpcCoder/encodeObject.spec.js @@ -0,0 +1,29 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const createCoder = require('./index'); + +describe('encodeObject', () => { + let coder; + + beforeEach(() => { + coder = createCoder(); + }); + + it('starts with id === 0 (nothing sent)', () => { + expect(coder.getId()).toEqual(0); + }); + + it('encodes a valid JsonRPC object', () => { + expect( + coder.encodeObject('method', 'params') + ).toEqual({ + id: 1, + jsonrpc: '2.0', + method: 'method', + params: 'params' + }); + expect(coder.getId()).toEqual(1); + }); +}); diff --git a/packages/api-provider/src/jsonRpcCoder/index.js b/packages/api-provider/src/jsonRpcCoder/index.js index f207791685af..b470fce1fe78 100644 --- a/packages/api-provider/src/jsonRpcCoder/index.js +++ b/packages/api-provider/src/jsonRpcCoder/index.js @@ -21,6 +21,8 @@ module.exports = function rpcCoder (): RpcCoder { encodeJson: (method: string, params: Array): string => encodeJson(self, method, params), encodeObject: (method: string, params: Array): JsonRpcRequest => - encodeObject(self, method, params) + encodeObject(self, method, params), + getId: (): number => + self.id }; }; diff --git a/packages/api-provider/src/types.js b/packages/api-provider/src/types.js index 576b4cfc3be1..e6e4e561f94c 100644 --- a/packages/api-provider/src/types.js +++ b/packages/api-provider/src/types.js @@ -25,10 +25,9 @@ export type JsonRpcResponse = JsonRpcObject & JsonRpcResponseBase; export type ProviderInterface$Callback = (error: ?Error, result: mixed) => void; -export interface ProviderInterface { - +isConnected: boolean; - - send (method: string, params: Array): Promise; - subscribe (method: string, params: Array, cb: ProviderInterface$Callback): Promise; - unsubscribe (id: number): Promise; +export type ProviderInterface = { + isConnected (): boolean, + send (method: string, params: Array): Promise, + subscribe (method: string, params: Array, cb: ProviderInterface$Callback): Promise, + unsubscribe (id: number): Promise } diff --git a/packages/api-provider/src/ws/connect.js b/packages/api-provider/src/ws/connect.js new file mode 100644 index 000000000000..83a2d2e5b3c3 --- /dev/null +++ b/packages/api-provider/src/ws/connect.js @@ -0,0 +1,20 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { WsState } from './types'; + +const onClose = require('./onClose'); +const onError = require('./onError'); +const onMessage = require('./onMessage'); +const onOpen = require('./onOpen'); + +module.exports = function connect (self: WsState): void { + self.websocket = new WebSocket(self.endpoint); + + self.websocket.onclose = onClose(self); + self.websocket.onerror = onError(self); + self.websocket.onmessage = onMessage(self); + self.websocket.onopen = onOpen(self); +}; diff --git a/packages/api-provider/src/ws/index.js b/packages/api-provider/src/ws/index.js index 114d4236875b..ce8481227cba 100644 --- a/packages/api-provider/src/ws/index.js +++ b/packages/api-provider/src/ws/index.js @@ -3,139 +3,31 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { JsonRpcResponse, ProviderInterface$Callback } from '../types'; - -type Awaiting = { - callback: (error: ?Error, result: mixed) => void -}; +import type { ProviderInterface, ProviderInterface$Callback } from '../types'; require('./polyfill'); -const l = require('@polkadot/util/logger')('ws-provider'); -const assert = require('@polkadot/util/assert'); -const JsonRpcCoder = require('../jsonRpcCoder'); - -module.exports = class WsProvider extends JsonRpcCoder implements ProviderInterface$Subscribe { - _autoConnect: boolean = true; - _endpoint: string; - _handlers: { [number]: Awaiting } = {}; - _isConnected: boolean = false; - _queued: { [number]: string } = {}; - _websocket: WebSocket; - - constructor (endpoint: string, autoConnect: boolean = true) { - super(); - - assert(/^ws:\/\//.test(endpoint), `Endpoint should start with 'ws://', received '${endpoint}'`); - - this._endpoint = endpoint; - this._autoConnect = autoConnect; - - if (autoConnect) { - this.connect(); - } - } - - // flowlint-next-line unsafe-getters-setters:off - get isConnected (): boolean { - return this._isConnected; - } - - connect = () => { - this._websocket = new WebSocket(this._endpoint); - - this._websocket.onclose = this._onClose; - this._websocket.onerror = this._onError; - this._websocket.onmessage = this._onMessage; - this._websocket.onopen = this._onOpen; - } - - _onClose = () => { - l.debug(() => ['disconnected from', this._endpoint]); - - this._isConnected = false; - - if (this._autoConnect) { - setTimeout(this.connect, 1000); - } - } - - _onError = (error: Event) => { - l.error(error); - } - - _onOpen = () => { - l.debug(() => ['connected to', this._endpoint]); - - this._isConnected = true; - - Object.keys(this._queued).forEach((id) => { - try { - this._websocket.send( - // flowlint-next-line unclear-type:off - this._queued[((id: any): number)] - ); - - // flowlint-next-line unclear-type:off - delete this._queued[((id: any): number)]; - } catch (error) { - l.error(error); - } - }); - } - - _onMessage = (message: MessageEvent): void => { - // flowlint-next-line unclear-type:off - const response: JsonRpcResponse = JSON.parse(((message.data: any): string)); - const handler = this._handlers[response.id]; - - if (!handler) { - l.error(`Unable to find handler for id=${response.id}`); - return; - } - - try { - const result = this.decodeResponse(response); - - handler.callback(null, result); - } catch (error) { - handler.callback(error); - } - - delete this._handlers[response.id]; - } - - send (method: string, params: Array): Promise { - return new Promise((resolve, reject): void => { - try { - const json = this.encodeJson(method, params); - - this._handlers[this.id] = { - callback: (error: ?Error, result: mixed) => { - if (error) { - reject(error); - } else { - resolve(result); - } - } - }; - - if (this._isConnected) { - this._websocket.send(json); - } else { - this._queued[this.id] = json; - } - } catch (error) { - reject(error); - } - }); - } - - subscribe (method: string, params: Array, cb: ProviderInterface$Callback): Promise { - throw new Error('Subscriptions has not been implemented'); - } - - unsubscribe (id: number): Promise { - throw new Error('Subscriptions has not been implemented'); - } +const connect = require('./connect'); +const send = require('./send'); +const state = require('./state'); +const subscribe = require('./subscribe'); +const unsubscribe = require('./unsubscribe'); + +module.exports = function wsProvider (endpoint: string, autoConnect: boolean = true): ProviderInterface { + const self = state(endpoint, autoConnect); + + if (autoConnect) { + connect(self); + } + + return { + isConnected: (): boolean => + self.isConnected, + send: (method: string, params: Array): Promise => + send(self, method, params), + subscribe: (method: string, params: Array, cb: ProviderInterface$Callback): Promise => + subscribe(self, method, params, cb), + unsubscribe: (id: number): Promise => + unsubscribe(self, id) + }; }; diff --git a/packages/api-provider/src/ws/index.spec.js b/packages/api-provider/src/ws/index.spec.js index 6ff1c4d335d0..504f457487db 100644 --- a/packages/api-provider/src/ws/index.spec.js +++ b/packages/api-provider/src/ws/index.spec.js @@ -4,7 +4,7 @@ const { mockWs, TEST_WS_URL } = require('../../test/mockWs'); -const Ws = require('./index'); +const create = require('./index'); let ws; let mock; @@ -13,7 +13,7 @@ let decodeSpy; function createWs (requests, autoConnect) { mock = mockWs(requests); - ws = new Ws(TEST_WS_URL, autoConnect); + ws = create(TEST_WS_URL, autoConnect); encodeSpy = jest.spyOn(ws, 'encodeObject'); decodeSpy = jest.spyOn(ws, 'decodeResponse'); @@ -39,12 +39,6 @@ describe('Ws', () => { } }); - it('requires an ws:// prefixed endpoint', () => { - expect( - () => new Ws('http://') - ).toThrow(/with 'ws/); - }); - describe('websocket', () => { let errorSpy; diff --git a/packages/api-provider/src/ws/onClose.js b/packages/api-provider/src/ws/onClose.js new file mode 100644 index 000000000000..c2df774c4b09 --- /dev/null +++ b/packages/api-provider/src/ws/onClose.js @@ -0,0 +1,20 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { WsState } from './types'; + +const connect = require('./connect'); + +module.exports = function onClose (self: WsState): () => void { + return (): void => { + self.l.debug(() => ['disconnected from', self.endpoint]); + + self.isConnected = false; + + if (self.autoConnect) { + setTimeout(() => connect(self), 1000); + } + }; +}; diff --git a/packages/api-provider/src/ws/onError.js b/packages/api-provider/src/ws/onError.js new file mode 100644 index 000000000000..87f5d5b08d17 --- /dev/null +++ b/packages/api-provider/src/ws/onError.js @@ -0,0 +1,12 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { WsState } from './types'; + +module.exports = function onError (self: WsState): (Event) => void { + return (error: Event): void => { + self.l.error(error); + }; +}; diff --git a/packages/api-provider/src/ws/onMessage.js b/packages/api-provider/src/ws/onMessage.js new file mode 100644 index 000000000000..c877eab96460 --- /dev/null +++ b/packages/api-provider/src/ws/onMessage.js @@ -0,0 +1,29 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { WsState } from './types'; + +module.exports = function onMessage (self: WsState): (MessageEvent) => void { + return (message: MessageEvent): void => { + // flowlint-next-line unclear-type:off + const response: JsonRpcResponse = JSON.parse(((message.data: any): string)); + const handler = self.handlers[response.id]; + + if (!handler) { + self.l.error(`Unable to find handler for id=${response.id}`); + return; + } + + try { + const result = self.coder.decodeResponse(response); + + handler.callback(null, result); + } catch (error) { + handler.callback(error); + } + + delete self.handlers[response.id]; + }; +}; diff --git a/packages/api-provider/src/ws/onOpen.js b/packages/api-provider/src/ws/onOpen.js new file mode 100644 index 000000000000..36807152fb1f --- /dev/null +++ b/packages/api-provider/src/ws/onOpen.js @@ -0,0 +1,28 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { WsState } from './types'; + +module.exports = function onOpen (self: WsState): () => void { + return (): void => { + self.l.debug(() => ['connected to', self.endpoint]); + + self.isConnected = true; + + Object.keys(self.queued).forEach((id) => { + try { + self.websocket.send( + // flowlint-next-line unclear-type:off + self.queued[((id: any): number)] + ); + + // flowlint-next-line unclear-type:off + delete self.queued[((id: any): number)]; + } catch (error) { + self.l.error(error); + } + }); + }; +}; diff --git a/packages/api-provider/src/ws/send.js b/packages/api-provider/src/ws/send.js new file mode 100644 index 000000000000..a2657ddf47f9 --- /dev/null +++ b/packages/api-provider/src/ws/send.js @@ -0,0 +1,32 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { WsState } from './types'; + +module.exports = async function send (self: WsState, method: string, params: Array): Promise { + return new Promise((resolve, reject): void => { + try { + const json = self.coder.encodeJson(method, params); + + self.handlers[this.coder.getId()] = { + callback: (error: ?Error, result: mixed) => { + if (error) { + reject(error); + } else { + resolve(result); + } + } + }; + + if (self.isConnected) { + self.websocket.send(json); + } else { + self.queued[this.id] = json; + } + } catch (error) { + reject(error); + } + }); +}; diff --git a/packages/api-provider/src/ws/state.js b/packages/api-provider/src/ws/state.js new file mode 100644 index 000000000000..beca53cfd56e --- /dev/null +++ b/packages/api-provider/src/ws/state.js @@ -0,0 +1,25 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { WsState } from './types'; + +const assert = require('@polkadot/util/assert'); +const l = require('@polkadot/util/logger')('ws-provider'); + +const coder = require('../jsonRpcCoder'); + +module.exports = function state (endpoint: string, autoConnect: boolean): $Shape { + assert(/^ws:\/\//.test(endpoint), `Endpoint should start with 'ws://', received '${endpoint}'`); + + return { + autoConnect, + coder: coder(), + endpoint, + handlers: {}, + isConnected: false, + l, + queued: {} + }; +}; diff --git a/packages/api-provider/src/ws/state.spec.js b/packages/api-provider/src/ws/state.spec.js new file mode 100644 index 000000000000..cfee5e4bff65 --- /dev/null +++ b/packages/api-provider/src/ws/state.spec.js @@ -0,0 +1,13 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const state = require('./state'); + +describe('state', () => { + it('requires an ws:// prefixed endpoint', () => { + expect( + () => state('http://') + ).toThrow(/with 'ws/); + }); +}); diff --git a/packages/api-provider/src/ws/subscribe.js b/packages/api-provider/src/ws/subscribe.js new file mode 100644 index 000000000000..65a36d5f4610 --- /dev/null +++ b/packages/api-provider/src/ws/subscribe.js @@ -0,0 +1,10 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { WsState } from './types'; + +module.exports = async function subscribe (self: WsState, method: string, params: Array, cb: ProviderInterface$Callback): Promise { + throw new Error('Subscriptions has not been implemented'); +}; diff --git a/packages/api-provider/src/ws/types.js b/packages/api-provider/src/ws/types.js new file mode 100644 index 000000000000..1eef8e06772c --- /dev/null +++ b/packages/api-provider/src/ws/types.js @@ -0,0 +1,21 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { Logger } from '@polkadot/util/types'; +import type { RpcCoder } from '../jsonRpcCoder'; + +export type WsState$Awaiting = { + callback: (error: ?Error, result: mixed) => void +}; + +export type WsState = { + coder: RpcCoder, + endpoint: string, + handlers: { [number]: WsState$Awaiting }, + isConnected: boolean, + l: Logger, + queued: { [number]: string }, + websocket: WebSocket +}; diff --git a/packages/api-provider/src/ws/unsubscribe.js b/packages/api-provider/src/ws/unsubscribe.js new file mode 100644 index 000000000000..6ce135dc5127 --- /dev/null +++ b/packages/api-provider/src/ws/unsubscribe.js @@ -0,0 +1,10 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { WsState } from './types'; + +module.exports = async function unsubscribe (self: WsState, id: number): Promise { + throw new Error('Subscriptions has not been implemented'); +}; From 0bf8313963949736da89e91beb4658f73347ecff Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 15 Mar 2018 11:43:34 +0100 Subject: [PATCH 5/8] Functional split completed --- .../json}/decodeResponse.js | 2 +- .../json}/decodeResponse.spec.js | 0 .../json}/encodeJson.js | 0 .../json}/encodeJson.spec.js | 0 .../json}/encodeObject.js | 2 +- .../json}/encodeObject.spec.js | 0 .../src/{jsonRpcCoder => coder/json}/index.js | 2 +- .../src/{jsonRpcCoder => coder/json}/types.js | 3 +- packages/api-provider/src/http/index.spec.js | 14 +- packages/api-provider/src/http/send.spec.js | 42 ---- packages/api-provider/src/http/state.js | 4 +- packages/api-provider/src/ws/connect.spec.js | 34 ++++ packages/api-provider/src/ws/index.js | 2 + packages/api-provider/src/ws/index.spec.js | 192 +----------------- packages/api-provider/src/ws/onClose.spec.js | 51 +++++ packages/api-provider/src/ws/onError.spec.js | 28 +++ .../api-provider/src/ws/onMessage.spec.js | 28 +++ packages/api-provider/src/ws/send.js | 20 +- packages/api-provider/src/ws/send.spec.js | 95 +++++++++ packages/api-provider/src/ws/state.js | 4 +- packages/api-provider/src/ws/types.js | 1 + 21 files changed, 278 insertions(+), 246 deletions(-) rename packages/api-provider/src/{jsonRpcCoder => coder/json}/decodeResponse.js (94%) rename packages/api-provider/src/{jsonRpcCoder => coder/json}/decodeResponse.spec.js (100%) rename packages/api-provider/src/{jsonRpcCoder => coder/json}/encodeJson.js (100%) rename packages/api-provider/src/{jsonRpcCoder => coder/json}/encodeJson.spec.js (100%) rename packages/api-provider/src/{jsonRpcCoder => coder/json}/encodeObject.js (88%) rename packages/api-provider/src/{jsonRpcCoder => coder/json}/encodeObject.spec.js (100%) rename packages/api-provider/src/{jsonRpcCoder => coder/json}/index.js (92%) rename packages/api-provider/src/{jsonRpcCoder => coder/json}/types.js (81%) create mode 100644 packages/api-provider/src/ws/connect.spec.js create mode 100644 packages/api-provider/src/ws/onClose.spec.js create mode 100644 packages/api-provider/src/ws/onError.spec.js create mode 100644 packages/api-provider/src/ws/onMessage.spec.js create mode 100644 packages/api-provider/src/ws/send.spec.js diff --git a/packages/api-provider/src/jsonRpcCoder/decodeResponse.js b/packages/api-provider/src/coder/json/decodeResponse.js similarity index 94% rename from packages/api-provider/src/jsonRpcCoder/decodeResponse.js rename to packages/api-provider/src/coder/json/decodeResponse.js index 39154bea48da..9847ea8770a1 100644 --- a/packages/api-provider/src/jsonRpcCoder/decodeResponse.js +++ b/packages/api-provider/src/coder/json/decodeResponse.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { JsonRpcResponse } from '../types'; +import type { JsonRpcResponse } from '../../types'; import type { RpcCoderState } from './types'; const assert = require('@polkadot/util/assert'); diff --git a/packages/api-provider/src/jsonRpcCoder/decodeResponse.spec.js b/packages/api-provider/src/coder/json/decodeResponse.spec.js similarity index 100% rename from packages/api-provider/src/jsonRpcCoder/decodeResponse.spec.js rename to packages/api-provider/src/coder/json/decodeResponse.spec.js diff --git a/packages/api-provider/src/jsonRpcCoder/encodeJson.js b/packages/api-provider/src/coder/json/encodeJson.js similarity index 100% rename from packages/api-provider/src/jsonRpcCoder/encodeJson.js rename to packages/api-provider/src/coder/json/encodeJson.js diff --git a/packages/api-provider/src/jsonRpcCoder/encodeJson.spec.js b/packages/api-provider/src/coder/json/encodeJson.spec.js similarity index 100% rename from packages/api-provider/src/jsonRpcCoder/encodeJson.spec.js rename to packages/api-provider/src/coder/json/encodeJson.spec.js diff --git a/packages/api-provider/src/jsonRpcCoder/encodeObject.js b/packages/api-provider/src/coder/json/encodeObject.js similarity index 88% rename from packages/api-provider/src/jsonRpcCoder/encodeObject.js rename to packages/api-provider/src/coder/json/encodeObject.js index 5a205b15b943..66400e1f74cd 100644 --- a/packages/api-provider/src/jsonRpcCoder/encodeObject.js +++ b/packages/api-provider/src/coder/json/encodeObject.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { JsonRpcRequest } from '../types'; +import type { JsonRpcRequest } from '../../types'; import type { RpcCoderState } from './types'; module.exports = function encodeObject (self: RpcCoderState, method: string, params: Array): JsonRpcRequest { diff --git a/packages/api-provider/src/jsonRpcCoder/encodeObject.spec.js b/packages/api-provider/src/coder/json/encodeObject.spec.js similarity index 100% rename from packages/api-provider/src/jsonRpcCoder/encodeObject.spec.js rename to packages/api-provider/src/coder/json/encodeObject.spec.js diff --git a/packages/api-provider/src/jsonRpcCoder/index.js b/packages/api-provider/src/coder/json/index.js similarity index 92% rename from packages/api-provider/src/jsonRpcCoder/index.js rename to packages/api-provider/src/coder/json/index.js index b470fce1fe78..1043891352a5 100644 --- a/packages/api-provider/src/jsonRpcCoder/index.js +++ b/packages/api-provider/src/coder/json/index.js @@ -3,7 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { JsonRpcRequest, JsonRpcResponse } from '../types'; +import type { JsonRpcRequest, JsonRpcResponse } from '../../types'; import type { RpcCoder, RpcCoderState } from './types'; const decodeResponse = require('./decodeResponse'); diff --git a/packages/api-provider/src/jsonRpcCoder/types.js b/packages/api-provider/src/coder/json/types.js similarity index 81% rename from packages/api-provider/src/jsonRpcCoder/types.js rename to packages/api-provider/src/coder/json/types.js index d0f203839433..1c77f81a379e 100644 --- a/packages/api-provider/src/jsonRpcCoder/types.js +++ b/packages/api-provider/src/coder/json/types.js @@ -6,7 +6,8 @@ export type RpcCoder = { decodeResponse: (response: JsonRpcResponse) => mixed, encodeObject: (method: string, params: Array) => JsonRpcRequest, - encodeJson: (method: string, params: Array) => string + encodeJson: (method: string, params: Array) => string, + getId: () => number }; export type RpcCoderState = { diff --git a/packages/api-provider/src/http/index.spec.js b/packages/api-provider/src/http/index.spec.js index e5814d80e087..3f89fd7a6c94 100644 --- a/packages/api-provider/src/http/index.spec.js +++ b/packages/api-provider/src/http/index.spec.js @@ -14,6 +14,18 @@ describe('Http', () => { }); it('always returns isConnected true', () => { - expect(http.isConnected).toEqual(true); + expect(http.isConnected()).toEqual(true); + }); + + it('does not (yet) support subscribe', () => { + return http.subscribe().catch((error) => { + expect(error.message).toMatch(/has not been implemented/); + }); + }); + + it('does not (yet) support unsubscribe', () => { + return http.unsubscribe().catch((error) => { + expect(error.message).toMatch(/has not been implemented/); + }); }); }); diff --git a/packages/api-provider/src/http/send.spec.js b/packages/api-provider/src/http/send.spec.js index fdd9659189e5..b43e9995d833 100644 --- a/packages/api-provider/src/http/send.spec.js +++ b/packages/api-provider/src/http/send.spec.js @@ -9,60 +9,18 @@ const createHttp = require('./index'); describe('send', () => { let http; let mock; - let encodeSpy; - let decodeSpy; beforeEach(() => { http = createHttp(TEST_HTTP_URL); - - encodeSpy = jest.spyOn(http, 'encodeJson'); - decodeSpy = jest.spyOn(http, 'decodeResponse'); }); afterEach(() => { - encodeSpy.mockRestore(); - decodeSpy.mockRestore(); - if (mock) { mock.done(); mock = null; } }); - it('encodes requests', () => { - mock = mockHttp([{ - method: 'test_encoding', - reply: { - result: 'ok' - } - }]); - - return http - .send('test_encoding', ['param']) - .then((result) => { - expect(encodeSpy).toHaveBeenCalledWith('test_encoding', ['param']); - }); - }); - - it('decodes responses', () => { - mock = mockHttp([{ - method: 'test_encoding', - reply: { - result: 'ok' - } - }]); - - return http - .send('test_encoding', ['param']) - .then((result) => { - expect(decodeSpy).toHaveBeenCalledWith({ - id: 1, - jsonrpc: '2.0', - result: 'ok' - }); - }); - }); - it('passes the body through correctly', () => { mock = mockHttp([{ method: 'test_body', diff --git a/packages/api-provider/src/http/state.js b/packages/api-provider/src/http/state.js index 4c3c8b2901f8..d308696c11c1 100644 --- a/packages/api-provider/src/http/state.js +++ b/packages/api-provider/src/http/state.js @@ -6,9 +6,9 @@ import type { HttpState } from './types'; const assert = require('@polkadot/util/assert'); -const l = require('@polkadot/util/logger')('http-provider'); +const l = require('@polkadot/util/logger')('api-http'); -const coder = require('../jsonRpcCoder'); +const coder = require('../coder/json'); module.exports = function state (endpoint: string): HttpState { assert(/^http:\/\//.test(endpoint), `Endpoint should start with 'http://', received '${endpoint}'`); diff --git a/packages/api-provider/src/ws/connect.spec.js b/packages/api-provider/src/ws/connect.spec.js new file mode 100644 index 000000000000..16124cb33766 --- /dev/null +++ b/packages/api-provider/src/ws/connect.spec.js @@ -0,0 +1,34 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const { mockWs, TEST_WS_URL } = require('../../test/mockWs'); + +const createState = require('./state'); +const connect = require('./connect'); + +describe('onError', () => { + let mock; + + beforeEach(() => { + mock = mockWs([]); + }); + + afterEach(() => { + if (mock) { + mock.done(); + mock = null; + } + }); + + it('sets up the on* handlers', () => { + const state = createState(TEST_WS_URL, false); + + connect(state); + + expect(state.websocket.onclose[0]).toBeDefined(); + expect(state.websocket.onerror[0]).toBeDefined(); + expect(state.websocket.onmessage[0]).toBeDefined(); + expect(state.websocket.onopen[0]).toBeDefined(); + }); +}); diff --git a/packages/api-provider/src/ws/index.js b/packages/api-provider/src/ws/index.js index ce8481227cba..ecce3d069e0c 100644 --- a/packages/api-provider/src/ws/index.js +++ b/packages/api-provider/src/ws/index.js @@ -21,6 +21,8 @@ module.exports = function wsProvider (endpoint: string, autoConnect: boolean = t } return { + connect: (): void => + connect(self), isConnected: (): boolean => self.isConnected, send: (method: string, params: Array): Promise => diff --git a/packages/api-provider/src/ws/index.spec.js b/packages/api-provider/src/ws/index.spec.js index 504f457487db..ff94cd9fc515 100644 --- a/packages/api-provider/src/ws/index.spec.js +++ b/packages/api-provider/src/ws/index.spec.js @@ -8,202 +8,22 @@ const create = require('./index'); let ws; let mock; -let encodeSpy; -let decodeSpy; function createWs (requests, autoConnect) { mock = mockWs(requests); ws = create(TEST_WS_URL, autoConnect); - encodeSpy = jest.spyOn(ws, 'encodeObject'); - decodeSpy = jest.spyOn(ws, 'decodeResponse'); - return ws; } describe('Ws', () => { afterEach(() => { - if (encodeSpy) { - encodeSpy.mockRestore(); - encodeSpy = null; - } - - if (decodeSpy) { - decodeSpy.mockRestore(); - decodeSpy = null; - } - if (mock) { mock.done(); mock = null; } }); - describe('websocket', () => { - let errorSpy; - - beforeEach(() => { - ws = createWs([]); - - errorSpy = jest.spyOn(console, 'error'); - }); - - afterEach(() => { - errorSpy.mockRestore(); - }); - - it('sets up the on* handlers', () => { - expect(ws._websocket.onclose[0]).toEqual(ws._onClose); - expect(ws._websocket.onerror[0]).toEqual(ws._onError); - expect(ws._websocket.onmessage[0]).toEqual(ws._onMessage); - expect(ws._websocket.onopen[0]).toEqual(ws._onOpen); - }); - - describe('_onClose', () => { - beforeEach(() => { - jest.useFakeTimers(); - }); - - afterEach(() => { - jest.useRealTimers(); - }); - - it('reconnects after delay', () => { - ws.connect = jest.fn(); - ws._onClose(); - - expect(ws.connect).not.toHaveBeenCalled(); - - jest.runAllTimers(); - - expect(ws.connect).toHaveBeenCalled(); - }); - - it('sets isConnected false', () => { - expect(ws.isConnected).toEqual(false); - }); - - it('does not reconnect when autoConnect false', () => { - mock.done(); - ws = createWs([], false); - - ws.connect = jest.fn(); - ws._onClose(); - - expect(ws.connect).not.toHaveBeenCalled(); - - jest.runAllTimers(); - - expect(ws.connect).not.toHaveBeenCalled(); - }); - }); - - describe('_onError', () => { - it('logs the error', () => { - ws._onError('test error'); - - expect(errorSpy).toHaveBeenCalledWith( - expect.anything(), expect.anything(), 'test error' - ); - }); - }); - - describe('_onMessage', () => { - it('fails with log when handler not found', () => { - ws._onMessage({ data: '{"id":2}' }); - - expect(errorSpy).toHaveBeenCalledWith( - expect.anything(), expect.anything(), 'Unable to find handler for id=2' - ); - }); - }); - }); - - describe('send', () => { - it('handles internal errors', () => { - ws = createWs([]); - - ws._isConnected = true; - ws._websocket = null; - - return ws - .send('test_encoding', ['param']) - .catch((error) => { - expect(error).toBeDefined(); - }); - }); - - it('encodes requests', () => { - ws = createWs([{ - id: 1, - method: 'test_encoding', - reply: { - result: 'ok' - } - }]); - - return ws - .send('test_encoding', ['param']) - .then((result) => { - expect(encodeSpy).toHaveBeenCalledWith('test_encoding', ['param']); - }); - }); - - it('decodes responses', () => { - ws = createWs([{ - id: 1, - method: 'test_encoding', - reply: { - result: 'ok' - } - }]); - - return ws - .send('test_encoding', ['param']) - .then((result) => { - expect(decodeSpy).toHaveBeenCalledWith({ - id: 1, - jsonrpc: '2.0', - result: 'ok' - }); - }); - }); - - it('passes the body through correctly', () => { - ws = createWs([{ - id: 1, - method: 'test_body', - reply: { - result: 'ok' - } - }]); - - return ws - .send('test_body', ['param']) - .then((result) => { - expect( - mock.body['test_body'] - ).toEqual('{"id":1,"jsonrpc":"2.0","method":"test_body","params":["param"]}'); - }); - }); - - it('throws error when !response.ok', () => { - ws = createWs([{ - id: 1, - error: { - code: 666, - message: 'error' - } - }]); - - return ws - .send('test_error', []) - .catch((error) => { - expect(error.message).toMatch(/\[666\]: error/); - }); - }); - }); - describe('queued', () => { it('sends messages when connected', () => { const ws = createWs([{ @@ -229,15 +49,15 @@ describe('Ws', () => { }); it('does not (yet) support subscribe', () => { - expect( - () => ws.subscribe() - ).toThrow(/has not been implemented/); + return ws.subscribe().catch((error) => { + expect(error.message).toMatch(/has not been implemented/); + }); }); it('does not (yet) support unsubscribe', () => { - expect( - () => ws.unsubscribe() - ).toThrow(/has not been implemented/); + return ws.unsubscribe().catch((error) => { + expect(error.message).toMatch(/has not been implemented/); + }); }); }); }); diff --git a/packages/api-provider/src/ws/onClose.spec.js b/packages/api-provider/src/ws/onClose.spec.js new file mode 100644 index 000000000000..dba25fdd4d49 --- /dev/null +++ b/packages/api-provider/src/ws/onClose.spec.js @@ -0,0 +1,51 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const { TEST_WS_URL } = require('../../test/mockWs'); + +const createState = require('./state'); + +describe('onClose', () => { + let state; + let mockConnect; + let onClose; + + beforeEach(() => { + mockConnect = jest.fn(); + + jest.mock('./connect', () => mockConnect); + jest.useFakeTimers(); + + state = createState(TEST_WS_URL, true); + onClose = require('./onClose')(state); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('reconnects after delay', () => { + onClose(); + + expect(mockConnect).not.toHaveBeenCalled(); + + jest.runAllTimers(); + + expect(mockConnect).toHaveBeenCalled(); + }); + + it('sets isConnected false', () => { + expect(state.isConnected).toEqual(false); + }); + + it('does not reconnect when autoConnect false', () => { + onClose(); + + expect(mockConnect).not.toHaveBeenCalled(); + + jest.runAllTimers(); + + expect(mockConnect).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/api-provider/src/ws/onError.spec.js b/packages/api-provider/src/ws/onError.spec.js new file mode 100644 index 000000000000..2d5b3c7ecb3f --- /dev/null +++ b/packages/api-provider/src/ws/onError.spec.js @@ -0,0 +1,28 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const onError = require('./onError'); +const createState = require('./state'); + +describe('onError', () => { + let state; + let errorSpy; + + beforeEach(() => { + state = createState('ws://127.0.0.1:1234', false); + errorSpy = jest.spyOn(console, 'error'); + }); + + afterEach(() => { + errorSpy.mockRestore(); + }); + + it('logs the error', () => { + onError(state)('test error'); + + expect(errorSpy).toHaveBeenCalledWith( + expect.anything(), expect.anything(), 'test error' + ); + }); +}); diff --git a/packages/api-provider/src/ws/onMessage.spec.js b/packages/api-provider/src/ws/onMessage.spec.js new file mode 100644 index 000000000000..16ecc866c25f --- /dev/null +++ b/packages/api-provider/src/ws/onMessage.spec.js @@ -0,0 +1,28 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const onMessage = require('./onMessage'); +const createState = require('./state'); + +describe('onError', () => { + let state; + let errorSpy; + + beforeEach(() => { + state = createState('ws://127.0.0.1:1234', false); + errorSpy = jest.spyOn(console, 'error'); + }); + + afterEach(() => { + errorSpy.mockRestore(); + }); + + it('fails with log when handler not found', () => { + onMessage(state)({ data: '{"id":2}' }); + + expect(errorSpy).toHaveBeenCalledWith( + expect.anything(), expect.anything(), 'Unable to find handler for id=2' + ); + }); +}); diff --git a/packages/api-provider/src/ws/send.js b/packages/api-provider/src/ws/send.js index a2657ddf47f9..81d4435400ae 100644 --- a/packages/api-provider/src/ws/send.js +++ b/packages/api-provider/src/ws/send.js @@ -9,21 +9,23 @@ module.exports = async function send (self: WsState, method: string, params: Arr return new Promise((resolve, reject): void => { try { const json = self.coder.encodeJson(method, params); - - self.handlers[this.coder.getId()] = { - callback: (error: ?Error, result: mixed) => { - if (error) { - reject(error); - } else { - resolve(result); - } + const id = self.coder.getId(); + const callback = (error: ?Error, result: mixed) => { + if (error) { + reject(error); + } else { + resolve(result); } }; + self.handlers[id] = { + callback + }; + if (self.isConnected) { self.websocket.send(json); } else { - self.queued[this.id] = json; + self.queued[id] = json; } } catch (error) { reject(error); diff --git a/packages/api-provider/src/ws/send.spec.js b/packages/api-provider/src/ws/send.spec.js new file mode 100644 index 000000000000..2a5580145f70 --- /dev/null +++ b/packages/api-provider/src/ws/send.spec.js @@ -0,0 +1,95 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const { mockWs, TEST_WS_URL } = require('../../test/mockWs'); + +let ws; +let mock; + +function createMock (requests) { + mock = mockWs(requests); +} + +function createWs (autoConnect) { + ws = require('./index')(TEST_WS_URL, autoConnect); + + return ws; +} + +describe('send', () => { + let globalWs; + + beforeEach(() => { + globalWs = global.WebSocket; + }); + + afterEach(() => { + global.WebSocket = globalWs; + + if (mock) { + mock.done(); + mock = null; + } + }); + + it('handles internal errors', () => { + createMock([]); + + let websocket; + + global.WebSocket = class { + constructor () { + console.log('CONSTRUCT!'); + websocket = this; + } + + send () { + throw new Error('send error'); + } + }; + + ws = createWs(); + websocket.onopen(); + + return ws + .send('test_encoding', ['param']) + .catch((error) => { + expect(error.message).toEqual('send error'); + }); + }); + + it('passes the body through correctly', () => { + createMock([{ + id: 1, + method: 'test_body', + reply: { + result: 'ok' + } + }]); + + return createWs() + .send('test_body', ['param']) + .then((result) => { + expect( + mock.body['test_body'] + ).toEqual('{"id":1,"jsonrpc":"2.0","method":"test_body","params":["param"]}'); + }); + }); + + it('throws error when !response.ok', () => { + createMock([{ + id: 1, + error: { + code: 666, + message: 'error' + } + }]); + + return createWs() + .send('test_error', []) + .catch((error) => { + expect(error.message).toMatch(/\[666\]: error/); + }); + }); +}); diff --git a/packages/api-provider/src/ws/state.js b/packages/api-provider/src/ws/state.js index beca53cfd56e..3901eeeffc40 100644 --- a/packages/api-provider/src/ws/state.js +++ b/packages/api-provider/src/ws/state.js @@ -6,9 +6,9 @@ import type { WsState } from './types'; const assert = require('@polkadot/util/assert'); -const l = require('@polkadot/util/logger')('ws-provider'); +const l = require('@polkadot/util/logger')('api-ws'); -const coder = require('../jsonRpcCoder'); +const coder = require('../coder/json'); module.exports = function state (endpoint: string, autoConnect: boolean): $Shape { assert(/^ws:\/\//.test(endpoint), `Endpoint should start with 'ws://', received '${endpoint}'`); diff --git a/packages/api-provider/src/ws/types.js b/packages/api-provider/src/ws/types.js index 1eef8e06772c..b7edfa8466b6 100644 --- a/packages/api-provider/src/ws/types.js +++ b/packages/api-provider/src/ws/types.js @@ -11,6 +11,7 @@ export type WsState$Awaiting = { }; export type WsState = { + autoConnect: boolean, coder: RpcCoder, endpoint: string, handlers: { [number]: WsState$Awaiting }, From 72cdb9b9f2eb4e7771daa9f453818894b8bc85e6 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 15 Mar 2018 12:07:06 +0100 Subject: [PATCH 6/8] Split actual method subscription --- packages/api-provider/src/ws/index.spec.js | 21 ++-------- packages/api-provider/src/ws/onClose.spec.js | 13 +----- packages/api-provider/src/ws/onOpen.js | 4 +- packages/api-provider/src/ws/onOpen.spec.js | 43 ++++++++++++++++++++ packages/api-provider/src/ws/send.spec.js | 1 - packages/api/src/create/interface.js | 11 ++--- packages/api/src/create/interface.spec.js | 4 +- packages/api/src/create/subscribe.js | 29 ++++--------- packages/api/src/create/subscribeMethod.js | 32 +++++++++++++++ 9 files changed, 97 insertions(+), 61 deletions(-) create mode 100644 packages/api-provider/src/ws/onOpen.spec.js create mode 100644 packages/api/src/create/subscribeMethod.js diff --git a/packages/api-provider/src/ws/index.spec.js b/packages/api-provider/src/ws/index.spec.js index ff94cd9fc515..67621f6753ac 100644 --- a/packages/api-provider/src/ws/index.spec.js +++ b/packages/api-provider/src/ws/index.spec.js @@ -24,23 +24,10 @@ describe('Ws', () => { } }); - describe('queued', () => { - it('sends messages when connected', () => { - const ws = createWs([{ - id: 1, - method: 'test_queue', - reply: { - result: 'ok' - } - }], false); - const sendPromise = ws.send('test_queue', []); - - ws.connect(); - - return sendPromise.then((result) => { - expect(result).toEqual('ok'); - }); - }); + it('returns the connected state', () => { + expect( + createWs([]).isConnected() + ).toEqual(false); }); describe('pubsub', () => { diff --git a/packages/api-provider/src/ws/onClose.spec.js b/packages/api-provider/src/ws/onClose.spec.js index dba25fdd4d49..0fcc83caf918 100644 --- a/packages/api-provider/src/ws/onClose.spec.js +++ b/packages/api-provider/src/ws/onClose.spec.js @@ -7,18 +7,13 @@ const { TEST_WS_URL } = require('../../test/mockWs'); const createState = require('./state'); describe('onClose', () => { - let state; let mockConnect; - let onClose; beforeEach(() => { mockConnect = jest.fn(); jest.mock('./connect', () => mockConnect); jest.useFakeTimers(); - - state = createState(TEST_WS_URL, true); - onClose = require('./onClose')(state); }); afterEach(() => { @@ -26,7 +21,7 @@ describe('onClose', () => { }); it('reconnects after delay', () => { - onClose(); + require('./onClose')(createState(TEST_WS_URL, true))(); expect(mockConnect).not.toHaveBeenCalled(); @@ -35,12 +30,8 @@ describe('onClose', () => { expect(mockConnect).toHaveBeenCalled(); }); - it('sets isConnected false', () => { - expect(state.isConnected).toEqual(false); - }); - it('does not reconnect when autoConnect false', () => { - onClose(); + require('./onClose')(createState(TEST_WS_URL, false))(); expect(mockConnect).not.toHaveBeenCalled(); diff --git a/packages/api-provider/src/ws/onOpen.js b/packages/api-provider/src/ws/onOpen.js index 36807152fb1f..ed67f35a85e5 100644 --- a/packages/api-provider/src/ws/onOpen.js +++ b/packages/api-provider/src/ws/onOpen.js @@ -6,7 +6,7 @@ import type { WsState } from './types'; module.exports = function onOpen (self: WsState): () => void { - return (): void => { + return (): boolean => { self.l.debug(() => ['connected to', self.endpoint]); self.isConnected = true; @@ -24,5 +24,7 @@ module.exports = function onOpen (self: WsState): () => void { self.l.error(error); } }); + + return true; }; }; diff --git a/packages/api-provider/src/ws/onOpen.spec.js b/packages/api-provider/src/ws/onOpen.spec.js new file mode 100644 index 000000000000..8ffc6277b88a --- /dev/null +++ b/packages/api-provider/src/ws/onOpen.spec.js @@ -0,0 +1,43 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. + +const { mockWs, TEST_WS_URL } = require('../../test/mockWs'); + +const create = require('./index'); + +let ws; +let mock; + +function createWs (requests, autoConnect) { + mock = mockWs(requests); + ws = create(TEST_WS_URL, autoConnect); + + return ws; +} + +describe('onOpen', () => { + afterEach(() => { + if (mock) { + mock.done(); + mock = null; + } + }); + + it('sends messages when connected', () => { + const ws = createWs([{ + id: 1, + method: 'test_queue', + reply: { + result: 'ok' + } + }], false); + const sendPromise = ws.send('test_queue', []); + + ws.connect(); + + return sendPromise.then((result) => { + expect(result).toEqual('ok'); + }); + }); +}); diff --git a/packages/api-provider/src/ws/send.spec.js b/packages/api-provider/src/ws/send.spec.js index 2a5580145f70..27502afdf1bb 100644 --- a/packages/api-provider/src/ws/send.spec.js +++ b/packages/api-provider/src/ws/send.spec.js @@ -40,7 +40,6 @@ describe('send', () => { global.WebSocket = class { constructor () { - console.log('CONSTRUCT!'); websocket = this; } diff --git a/packages/api/src/create/interface.js b/packages/api/src/create/interface.js index bd91eb2a8910..a94486baf128 100644 --- a/packages/api/src/create/interface.js +++ b/packages/api/src/create/interface.js @@ -4,22 +4,17 @@ // @flow import type { InterfaceDefinition } from '@polkadot/api-jsonrpc/types'; -import type { ProviderInterface, ProviderInterface$Subscribe } from '@polkadot/api-provider/types'; +import type { ProviderInterface } from '@polkadot/api-provider/types'; import type { ApiInterface$Section } from '../types'; -const isFunction = require('@polkadot/util/is/function'); - const createMethod = require('./method'); const createSubscribe = require('./subscribe'); module.exports = function createInterface (provider: ProviderInterface, { methods }: InterfaceDefinition, section: string): ApiInterface$Section { const exposed: $Shape = {}; - const pubsub = (provider: ProviderInterface$Subscribe); - if (isFunction(pubsub.subscribe)) { - exposed.subscribe = createSubscribe(pubsub, section, methods); - exposed.unsubscribe = provider.unsubcribe; - } + exposed.subscribe = createSubscribe(provider, section, methods); + exposed.unsubscribe = provider.unsubcribe; return Object .keys(methods) diff --git a/packages/api/src/create/interface.spec.js b/packages/api/src/create/interface.spec.js index 72f943374a4a..3da42574af24 100644 --- a/packages/api/src/create/interface.spec.js +++ b/packages/api/src/create/interface.spec.js @@ -34,7 +34,9 @@ describe('createInterface', () => { }); it('adds the specified methods to the interface', () => { - expect(Object.keys(container)).toEqual(['blah', 'bleh']); + expect(Object.keys(container)).toEqual( + ['subscribe', 'unsubscribe', 'blah', 'bleh'] + ); }); it('had function calls for the attached methods', () => { diff --git a/packages/api/src/create/subscribe.js b/packages/api/src/create/subscribe.js index b2016830be0e..2b2effeb3912 100644 --- a/packages/api/src/create/subscribe.js +++ b/packages/api/src/create/subscribe.js @@ -4,37 +4,22 @@ // @flow import type { InterfaceDefinition$Methods } from '@polkadot/api-jsonrpc/types'; -import type { ProviderInterface$Subscribe, ProviderInterface$Subscribe$Callback } from '@polkadot/api-provider/types'; +import type { ProviderInterface$Subscribe, ProviderInterface$Callback } from '@polkadot/api-provider/types'; -const formatOutput = require('@polkadot/api-format/output'); -const ExtError = require('@polkadot/util/ext/error'); const assert = require('@polkadot/util/assert'); -const jsonrpcSignature = require('@polkadot/util/jsonrpc/signature'); -type Method = (..._params: Array) => Promise; +type Method = (name: string, params: Array, cb: ProviderInterface$Callback) => Promise; -const createParams = require('./params'); +const subscribeMethod = require('./subscribeMethod'); module.exports = function createSubscribe (provider: ProviderInterface$Subscribe, methods: InterfaceDefinition$Methods, section: string): Method { - return async (name: string, _params: Array, cb: ProviderInterface$Subscribe$Callback): Promise => { + return async (name: string, params: Array, cb: ProviderInterface$Callback): Promise => { const rpcName = `${section}_${name}`; assert(methods[name], `Unable to find '${rpcName}' subscription`); - const { inputs, output } = methods[name]; - - try { - const params = createParams(rpcName, _params, inputs); - - return provider.subscribe(rpcName, params, (error: ?Error, result: mixed) => { - if (error) { - cb(error); - } else { - cb(null, formatOutput(output, result)); - } - }); - } catch (error) { - throw new ExtError(`${jsonrpcSignature(rpcName, inputs, output)}:: ${error.message}`, (error: ExtError).code); - } + const fn = subscribeMethod(provider, rpcName, methods[name]); + + return fn(params, cb); }; }; diff --git a/packages/api/src/create/subscribeMethod.js b/packages/api/src/create/subscribeMethod.js new file mode 100644 index 000000000000..508aa6a3738c --- /dev/null +++ b/packages/api/src/create/subscribeMethod.js @@ -0,0 +1,32 @@ +// Copyright 2017-2018 Jaco Greeff +// This software may be modified and distributed under the terms +// of the ISC license. See the LICENSE file for details. +// @flow + +import type { ProviderInterface$Subscribe, ProviderInterface$Callback } from '@polkadot/api-provider/types'; + +const formatOutput = require('@polkadot/api-format/output'); +const ExtError = require('@polkadot/util/ext/error'); +const jsonrpcSignature = require('@polkadot/util/jsonrpc/signature'); + +type Method = (params: Array, cb: ProviderInterface$Callback) => Promise; + +const createParams = require('./params'); + +module.exports = function createSubscribeMethod (provider: ProviderInterface$Subscribe, rpcName: string, { inputs, output }: InterfaceMethodDefinition): Method { + return async (_params: Array, cb: ProviderInterface$Subscribe$Callback): Promise => { + try { + const params = createParams(rpcName, _params, inputs); + + return provider.subscribe(rpcName, params, (error: ?Error, result: mixed) => { + if (error) { + cb(error); + } else { + cb(null, formatOutput(output, result)); + } + }); + } catch (error) { + throw new ExtError(`${jsonrpcSignature(rpcName, inputs, output)}:: ${error.message}`, (error: ExtError).code); + } + }; +}; From a355974bccc8e9f2c11f6d5357c8b1deb5d0f5a0 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 15 Mar 2018 12:20:21 +0100 Subject: [PATCH 7/8] Update flow --- packages/api-provider/src/coder/json/types.js | 2 ++ packages/api-provider/src/http/subscribe.js | 1 + packages/api-provider/src/http/types.js | 2 +- packages/api-provider/src/ws/onMessage.js | 1 + packages/api-provider/src/ws/onOpen.js | 2 +- packages/api-provider/src/ws/subscribe.js | 1 + packages/api-provider/src/ws/types.js | 2 +- packages/api/src/create/interface.js | 2 +- packages/api/src/create/subscribe.js | 4 ++-- packages/api/src/create/subscribeMethod.js | 7 ++++--- packages/api/src/types.js | 3 ++- 11 files changed, 17 insertions(+), 10 deletions(-) diff --git a/packages/api-provider/src/coder/json/types.js b/packages/api-provider/src/coder/json/types.js index 1c77f81a379e..788d66e9fbf1 100644 --- a/packages/api-provider/src/coder/json/types.js +++ b/packages/api-provider/src/coder/json/types.js @@ -3,6 +3,8 @@ // of the ISC license. See the LICENSE file for details. // @flow +import type { JsonRpcRequest, JsonRpcResponse } from '../../types'; + export type RpcCoder = { decodeResponse: (response: JsonRpcResponse) => mixed, encodeObject: (method: string, params: Array) => JsonRpcRequest, diff --git a/packages/api-provider/src/http/subscribe.js b/packages/api-provider/src/http/subscribe.js index ded773c3f4a6..389c9374164c 100644 --- a/packages/api-provider/src/http/subscribe.js +++ b/packages/api-provider/src/http/subscribe.js @@ -3,6 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow +import type { ProviderInterface$Callback } from '../types'; import type { HttpState } from './types'; module.exports = async function subscribe (self: HttpState, method: string, params: Array, cb: ProviderInterface$Callback): Promise { diff --git a/packages/api-provider/src/http/types.js b/packages/api-provider/src/http/types.js index f314ab348e7c..2adf6124ceac 100644 --- a/packages/api-provider/src/http/types.js +++ b/packages/api-provider/src/http/types.js @@ -4,7 +4,7 @@ // @flow import type { Logger } from '@polkadot/util/types'; -import type { RpcCoder } from '../jsonRpcCoder'; +import type { RpcCoder } from '../coder/json/types'; export type HttpState = { coder: RpcCoder, diff --git a/packages/api-provider/src/ws/onMessage.js b/packages/api-provider/src/ws/onMessage.js index c877eab96460..7587deb3515c 100644 --- a/packages/api-provider/src/ws/onMessage.js +++ b/packages/api-provider/src/ws/onMessage.js @@ -3,6 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow +import type { JsonRpcResponse } from '../types'; import type { WsState } from './types'; module.exports = function onMessage (self: WsState): (MessageEvent) => void { diff --git a/packages/api-provider/src/ws/onOpen.js b/packages/api-provider/src/ws/onOpen.js index ed67f35a85e5..f816a39be90a 100644 --- a/packages/api-provider/src/ws/onOpen.js +++ b/packages/api-provider/src/ws/onOpen.js @@ -5,7 +5,7 @@ import type { WsState } from './types'; -module.exports = function onOpen (self: WsState): () => void { +module.exports = function onOpen (self: WsState): () => boolean { return (): boolean => { self.l.debug(() => ['connected to', self.endpoint]); diff --git a/packages/api-provider/src/ws/subscribe.js b/packages/api-provider/src/ws/subscribe.js index 65a36d5f4610..09dacc3f831b 100644 --- a/packages/api-provider/src/ws/subscribe.js +++ b/packages/api-provider/src/ws/subscribe.js @@ -3,6 +3,7 @@ // of the ISC license. See the LICENSE file for details. // @flow +import type { ProviderInterface$Callback } from '../types'; import type { WsState } from './types'; module.exports = async function subscribe (self: WsState, method: string, params: Array, cb: ProviderInterface$Callback): Promise { diff --git a/packages/api-provider/src/ws/types.js b/packages/api-provider/src/ws/types.js index b7edfa8466b6..201f08337d62 100644 --- a/packages/api-provider/src/ws/types.js +++ b/packages/api-provider/src/ws/types.js @@ -4,7 +4,7 @@ // @flow import type { Logger } from '@polkadot/util/types'; -import type { RpcCoder } from '../jsonRpcCoder'; +import type { RpcCoder } from '../coder/json/types'; export type WsState$Awaiting = { callback: (error: ?Error, result: mixed) => void diff --git a/packages/api/src/create/interface.js b/packages/api/src/create/interface.js index a94486baf128..faaff105b25f 100644 --- a/packages/api/src/create/interface.js +++ b/packages/api/src/create/interface.js @@ -14,7 +14,7 @@ module.exports = function createInterface (provider: ProviderInterface, { method const exposed: $Shape = {}; exposed.subscribe = createSubscribe(provider, section, methods); - exposed.unsubscribe = provider.unsubcribe; + exposed.unsubscribe = provider.unsubscribe; return Object .keys(methods) diff --git a/packages/api/src/create/subscribe.js b/packages/api/src/create/subscribe.js index 2b2effeb3912..bf5a36ce3623 100644 --- a/packages/api/src/create/subscribe.js +++ b/packages/api/src/create/subscribe.js @@ -4,7 +4,7 @@ // @flow import type { InterfaceDefinition$Methods } from '@polkadot/api-jsonrpc/types'; -import type { ProviderInterface$Subscribe, ProviderInterface$Callback } from '@polkadot/api-provider/types'; +import type { ProviderInterface, ProviderInterface$Callback } from '@polkadot/api-provider/types'; const assert = require('@polkadot/util/assert'); @@ -12,7 +12,7 @@ type Method = (name: string, params: Array, cb: ProviderInterface$Callbac const subscribeMethod = require('./subscribeMethod'); -module.exports = function createSubscribe (provider: ProviderInterface$Subscribe, methods: InterfaceDefinition$Methods, section: string): Method { +module.exports = function createSubscribe (provider: ProviderInterface, section: string, methods: InterfaceDefinition$Methods): Method { return async (name: string, params: Array, cb: ProviderInterface$Callback): Promise => { const rpcName = `${section}_${name}`; diff --git a/packages/api/src/create/subscribeMethod.js b/packages/api/src/create/subscribeMethod.js index 508aa6a3738c..b03e779399bf 100644 --- a/packages/api/src/create/subscribeMethod.js +++ b/packages/api/src/create/subscribeMethod.js @@ -3,7 +3,8 @@ // of the ISC license. See the LICENSE file for details. // @flow -import type { ProviderInterface$Subscribe, ProviderInterface$Callback } from '@polkadot/api-provider/types'; +import type { InterfaceMethodDefinition } from '@polkadot/api-jsonrpc/types'; +import type { ProviderInterface, ProviderInterface$Callback } from '@polkadot/api-provider/types'; const formatOutput = require('@polkadot/api-format/output'); const ExtError = require('@polkadot/util/ext/error'); @@ -13,8 +14,8 @@ type Method = (params: Array, cb: ProviderInterface$Callback) => Promise< const createParams = require('./params'); -module.exports = function createSubscribeMethod (provider: ProviderInterface$Subscribe, rpcName: string, { inputs, output }: InterfaceMethodDefinition): Method { - return async (_params: Array, cb: ProviderInterface$Subscribe$Callback): Promise => { +module.exports = function createSubscribeMethod (provider: ProviderInterface, rpcName: string, { inputs, output }: InterfaceMethodDefinition): Method { + return async (_params: Array, cb: ProviderInterface$Callback): Promise => { try { const params = createParams(rpcName, _params, inputs); diff --git a/packages/api/src/types.js b/packages/api/src/types.js index a8d47a55e601..f6d23b0ac88c 100644 --- a/packages/api/src/types.js +++ b/packages/api/src/types.js @@ -4,7 +4,8 @@ // @flow export type ApiInterface$Section = { - [string]: () => Promise + // flowlint-next-line unclear-type:off + [string]: Function }; export type ApiInterface = { From 9fe71cc6d0b5fad9e9a85bf4ea1552ecc9489a86 Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Thu, 15 Mar 2018 12:53:58 +0100 Subject: [PATCH 8/8] Flatten no user-specified array in sub call --- packages/api/src/create/subscribe.js | 8 ++++---- packages/api/src/create/subscribe.spec.js | 14 ++++++++++---- packages/api/src/create/subscribeMethod.js | 11 +++++++++-- packages/api/src/types.js | 8 ++++++-- 4 files changed, 29 insertions(+), 12 deletions(-) diff --git a/packages/api/src/create/subscribe.js b/packages/api/src/create/subscribe.js index bf5a36ce3623..25d39306536b 100644 --- a/packages/api/src/create/subscribe.js +++ b/packages/api/src/create/subscribe.js @@ -4,22 +4,22 @@ // @flow import type { InterfaceDefinition$Methods } from '@polkadot/api-jsonrpc/types'; -import type { ProviderInterface, ProviderInterface$Callback } from '@polkadot/api-provider/types'; +import type { ProviderInterface } from '@polkadot/api-provider/types'; const assert = require('@polkadot/util/assert'); -type Method = (name: string, params: Array, cb: ProviderInterface$Callback) => Promise; +type Method = (name: string, ...params: Array) => Promise; const subscribeMethod = require('./subscribeMethod'); module.exports = function createSubscribe (provider: ProviderInterface, section: string, methods: InterfaceDefinition$Methods): Method { - return async (name: string, params: Array, cb: ProviderInterface$Callback): Promise => { + return async (name: string, ...params: Array): Promise => { const rpcName = `${section}_${name}`; assert(methods[name], `Unable to find '${rpcName}' subscription`); const fn = subscribeMethod(provider, rpcName, methods[name]); - return fn(params, cb); + return fn.apply(null, params); }; }; diff --git a/packages/api/src/create/subscribe.spec.js b/packages/api/src/create/subscribe.spec.js index a4a3dc2c3af0..3f8a435268f0 100644 --- a/packages/api/src/create/subscribe.spec.js +++ b/packages/api/src/create/subscribe.spec.js @@ -35,7 +35,7 @@ describe('createSubscribe', () => { }) }; - sub = createSubscribe(provider, methods, 'test'); + sub = createSubscribe(provider, 'test', methods); }); it('it does not subscribe to not-found endpoint', () => { @@ -45,13 +45,13 @@ describe('createSubscribe', () => { }); it('returns the subscription', () => { - return sub('bleh', []).then((id) => { + return sub('bleh', () => true).then((id) => { expect(id).toEqual(12345); }); }); it('returns values as they are available', (done) => { - sub('bleh', [], () => { + sub('bleh', () => { done(); }); @@ -59,7 +59,7 @@ describe('createSubscribe', () => { }); it('returns errors as they are available', (done) => { - sub('bleh', [], (error) => { + sub('bleh', (error) => { expect(error.message).toEqual('test error'); done(); @@ -67,4 +67,10 @@ describe('createSubscribe', () => { cb(new Error('test error')); }); + + it('checks that valid callback is provided', () => { + return sub('bleh').catch((error) => { + expect(error.message).toMatch(/Expected callback in last position/); + }); + }); }); diff --git a/packages/api/src/create/subscribeMethod.js b/packages/api/src/create/subscribeMethod.js index b03e779399bf..385a67512767 100644 --- a/packages/api/src/create/subscribeMethod.js +++ b/packages/api/src/create/subscribeMethod.js @@ -7,16 +7,23 @@ import type { InterfaceMethodDefinition } from '@polkadot/api-jsonrpc/types'; import type { ProviderInterface, ProviderInterface$Callback } from '@polkadot/api-provider/types'; const formatOutput = require('@polkadot/api-format/output'); +const assert = require('@polkadot/util/assert'); const ExtError = require('@polkadot/util/ext/error'); +const isFunction = require('@polkadot/util/is/function'); const jsonrpcSignature = require('@polkadot/util/jsonrpc/signature'); -type Method = (params: Array, cb: ProviderInterface$Callback) => Promise; +type Method = (...params: Array) => Promise; const createParams = require('./params'); module.exports = function createSubscribeMethod (provider: ProviderInterface, rpcName: string, { inputs, output }: InterfaceMethodDefinition): Method { - return async (_params: Array, cb: ProviderInterface$Callback): Promise => { + return async (..._params: Array): Promise => { try { + // flowlint-next-line unclear-type:off + const cb = ((_params.pop(): any): ProviderInterface$Callback); + + assert(isFunction(cb), `Expected callback in last position of params`); + const params = createParams(rpcName, _params, inputs); return provider.subscribe(rpcName, params, (error: ?Error, result: mixed) => { diff --git a/packages/api/src/types.js b/packages/api/src/types.js index f6d23b0ac88c..b3ed0e145cd7 100644 --- a/packages/api/src/types.js +++ b/packages/api/src/types.js @@ -3,9 +3,13 @@ // of the ISC license. See the LICENSE file for details. // @flow +export type ApiInterface$Section$Method = (...params: Array) => Promise; + export type ApiInterface$Section = { - // flowlint-next-line unclear-type:off - [string]: Function + [string]: ApiInterface$Section$Method, + + subscribe: (name: string, ...params: Array) => Promise, + unsubscribe: (id: number) => Promise }; export type ApiInterface = {