diff --git a/.jshintrc b/.jshintrc index b81664a..f86ca6b 100644 --- a/.jshintrc +++ b/.jshintrc @@ -11,5 +11,6 @@ "devel" : true, "node" : true, "sub" : true, + "esversion": 6, "quotmark": "single" } \ No newline at end of file diff --git a/.mocharc.json b/.mocharc.json new file mode 100644 index 0000000..735bb7e --- /dev/null +++ b/.mocharc.json @@ -0,0 +1,5 @@ +{ + "reporter": "list", + "ui": "exports", + "check-leaks": true +} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 2ca91f2..0f064fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: node_js node_js: - - "0.10" - - "0.8" \ No newline at end of file + - "node" + - "lts/*" + - "10" \ No newline at end of file diff --git a/README.md b/README.md index b4f46e5..e721a06 100644 --- a/README.md +++ b/README.md @@ -1,157 +1,170 @@ -[![Build Status](https://travis-ci.org/pocesar/node-jsonrpc2.png?branch=master)](https://travis-ci.org/pocesar/node-jsonrpc2) - -[![NPM](https://nodei.co/npm/json-rpc2.png?downloads=true)](https://nodei.co/npm/json-rpc2/) - -# node-jsonrpc2 - -JSON-RPC 2.0 server and client library, with `HTTP` (with `Websocket` support) and `TCP` endpoints - -This fork is a rewrite with proper testing framework, linted code, compatible with node 0.8.x and 0.10.x, class inheritance, and added functionalities - -## Install - -To install node-jsonrpc2 in the current directory, run: - -```bash -npm install json-rpc2 --save -``` - -## Usage - -Firing up an efficient JSON-RPC server becomes extremely simple: - -```js -var rpc = require('json-rpc2'); - -var server = rpc.Server.create({ - 'websocket': true // is true by default - 'headers': { // allow custom headers is empty by default - 'Access-Control-Allow-Origin': '*' - } -}); - -function add(args, opt, callback) { - callback(null, args[0] + args[1]); -} - -server.expose('add', add); - -// you can expose an entire object as well: - -server.expose('namespace', { - 'function1': function(){}, - 'function2': function(){}, - 'function3': function(){} -}); -// expects calls to be namespace.function1, namespace.function2 and namespace.function3 - -// listen creates an HTTP server on localhost only -server.listen(8000, 'localhost'); -``` - -And creating a client to speak to that server is easy too: - -```js -var rpc = require('json-rpc2'); - -var client = rpc.Client.create(8000, 'localhost'); - -// Call add function on the server - -client.call('add', [1, 2], function(err, result) { - console.log('1 + 2 = ' + result); -}); -``` - -Create a raw (socket) server using: - -```js -var rpc = require('json-rpc2'); - -var server = rpc.Server.create(); - -// non-standard auth for RPC, when using this module using both client and server, works out-of-the-box -server.enableAuth('user', 'pass'); - -// Listen on socket -server.listenRaw(8080, 'localhost'); -``` - -## Extend, overwrite, overload - -Any class can be extended, or used as a mixin for new classes, since it uses [ES5Class](http://github.com/pocesar/ES5-Class) module. - -For example, you may extend the `Endpoint` class, that automatically extends `Client` and `Server` classes. -Extending `Connection` automatically extends `SocketConnection` and `HttpServerConnection`. - -```js -var rpc = require('json-rpc2'); - -rpc.Endpoint.include({ - 'newFunction': function(){ - - } -}); - -var - server = rpc.Server.create(), - client = rpc.Client.create(); - -server.newFunction(); // already available -client.newFunction(); // already available -``` - -To implement a new class method (that can be called without an instance, like `rpc.Endpoint.newFunction`: - -```js -var rpc = require('json-rpc2'); - -rpc.Endpoint.implement({ - 'newFunction': function(){ - } -}); - -rpc.Endpoint.newFunction(); // available -rpc.Client.newFunction(); // every -rpc.Server.newFunction(); // where -``` - -Don't forget, when you are overloading an existing function, you can call the original function using `$super` - -```js -var rpc = require('json-rpc2'); - -rpc.Endpoint.implement({ - 'trace': function(direction, message){ - this.$super(' (' + direction + ')', message); //call the last defined function - } -}); -``` - -And you can start your classes directly from any of the classes - -```js -var MyCoolServer = require('json-rpc2').Server.define('MyCoolServer', { - myOwnFunction: function(){ - }, -}, { - myOwnClassMethod: function(){ - } -}); // MyCoolServer will contain all class and instance functions from Server - -MyCoolServer.myOwnClassMethod(); // class function -MyCoolServer.create().myOwnFunction(); // instance function -``` - -## Debugging - -This module uses the [debug](http://github.com/visionmedia/debug) package, to debug it, you need to set the Node -environment variable to jsonrpc, by setting it in command line as `set DEBUG=jsonrpc` or `export DEBUG=jsonrpc` - -## Examples - -To learn more, see the `examples` directory, peruse `test/jsonrpc-test.js`, or -simply "Use The Source, Luke". - -More documentation and development is on its way. - +[![Build Status](https://travis-ci.org/pocesar/node-jsonrpc2.svg?branch=master)](https://travis-ci.org/pocesar/node-jsonrpc2) + +[![NPM](https://nodei.co/npm/json-rpc2.svg?downloads=true)](https://nodei.co/npm/json-rpc2/) + +# node-jsonrpc2 + +JSON-RPC 2.0 server and client library, with `HTTP` (with `Websocket` support) and `TCP` endpoints + +This fork is a rewrite with proper testing framework, linted code, compatible with node 0.8.x and 0.10.x, class inheritance, and added functionalities + +## Tools + +Check [jsonrpc2-tools](https://www.npmjs.org/package/jsonrpc2-tools) for some nice additions to this module. + +## Install + +To install node-jsonrpc2 in the current directory, run: + +```bash +npm install json-rpc2 --save +``` + +## Changes from 1.x + +* Uses native EventEmitter instead of EventEmitter3 + +## Changes from 0.x + +* Before, the `id` member was permissive and wouldn't actually adhere to the RFC, allowing anything besides `undefined`. +* If your application relied on weird id constructs other than `String`, `Number` or `null`, it might break if you update to 1.x + +## Usage + +Firing up an efficient JSON-RPC server becomes extremely simple: + +```js +var rpc = require('json-rpc2'); + +var server = rpc.Server.$create({ + 'websocket': true, // is true by default + 'headers': { // allow custom headers is empty by default + 'Access-Control-Allow-Origin': '*' + } +}); + +function add(args, opt, callback) { + callback(null, args[0] + args[1]); +} + +server.expose('add', add); + +// you can expose an entire object as well: + +server.expose('namespace', { + 'function1': function(){}, + 'function2': function(){}, + 'function3': function(){} +}); +// expects calls to be namespace.function1, namespace.function2 and namespace.function3 + +// listen creates an HTTP server on localhost only +server.listen(8000, 'localhost'); +``` + +And creating a client to speak to that server is easy too: + +```js +var rpc = require('json-rpc2'); + +var client = rpc.Client.$create(8000, 'localhost'); + +// Call add function on the server + +client.call('add', [1, 2], function(err, result) { + console.log('1 + 2 = ' + result); +}); +``` + +Create a raw (socket) server using: + +```js +var rpc = require('json-rpc2'); + +var server = rpc.Server.$create(); + +// non-standard auth for RPC, when using this module using both client and server, works out-of-the-box +server.enableAuth('user', 'pass'); + +// Listen on socket +server.listenRaw(8080, 'localhost'); +``` + +## Extend, overwrite, overload + +Any class can be extended, or used as a mixin for new classes, since it uses [ES5Class](http://github.com/pocesar/ES5-Class) module. + +For example, you may extend the `Endpoint` class, that automatically extends `Client` and `Server` classes. +Extending `Connection` automatically extends `SocketConnection` and `HttpServerConnection`. + +```js +var rpc = require('json-rpc2'); + +rpc.Endpoint.$include({ + 'newFunction': function(){ + + } +}); + +var + server = rpc.Server.$create(), + client = rpc.Client.$create(); + +server.newFunction(); // already available +client.newFunction(); // already available +``` + +To implement a new class method (that can be called without an instance, like `rpc.Endpoint.newFunction`): + +```js +var rpc = require('json-rpc2'); + +rpc.Endpoint.$implement({ + 'newFunction': function(){ + } +}); + +rpc.Endpoint.newFunction(); // available +rpc.Client.newFunction(); // every +rpc.Server.newFunction(); // where +``` + +Don't forget, when you are overloading an existing function, you can call the original function using `$super` + +```js +var rpc = require('json-rpc2'); + +rpc.Endpoint.$implement({ + 'trace': function($super, direction, message){ + $super(' (' + direction + ')', message); //call the last defined function + } +}); +``` + +And you can start your classes directly from any of the classes + +```js +var MyCoolServer = require('json-rpc2').Server.$define('MyCoolServer', { + myOwnFunction: function(){ + }, +}, { + myOwnClassMethod: function(){ + } +}); // MyCoolServer will contain all class and instance functions from Server + +MyCoolServer.myOwnClassMethod(); // class function +MyCoolServer.$create().myOwnFunction(); // instance function +``` + +## Debugging + +This module uses the [debug](http://github.com/visionmedia/debug) package, to debug it, you need to set the Node +environment variable to jsonrpc, by setting it in command line as `set DEBUG=jsonrpc` or `export DEBUG=jsonrpc` + +## Examples + +To learn more, see the `examples` directory, peruse `test/jsonrpc-test.js`, or +simply "Use The Source, Luke". + +More documentation and development is on its way. + diff --git a/examples/client.js b/examples/client.js index 45d555a..ab53fb3 100644 --- a/examples/client.js +++ b/examples/client.js @@ -4,7 +4,7 @@ var /* Connect to HTTP server */ -var client = rpc.Client.create(8088, 'localhost', 'myuser', 'secret123'); +var client = rpc.Client.$create(8088, 'localhost', 'myuser', 'secret123'); client.call('add', [1, 2], function (err, result){ if (err) { @@ -31,7 +31,7 @@ client.call('delayed.echo', ['Echo.', 1500], function (err, result){ /* Connect to Raw socket server */ -var socketClient = rpc.Client.create(8089, 'localhost', 'myuser', 'secret123'); +var socketClient = rpc.Client.$create(8089, 'localhost', 'myuser', 'secret123'); socketClient.connectSocket(function (err, conn){ if (err) { @@ -67,7 +67,7 @@ socketClient.connectSocket(function (err, conn){ /* Connect to Websocket server */ -var WebsocketClient = rpc.Client.create(8088, 'localhost', 'myuser', 'secret123'); +var WebsocketClient = rpc.Client.$create(8088, 'localhost', 'myuser', 'secret123'); WebsocketClient.connectWebsocket(function (err, conn){ if (err) { diff --git a/examples/server.js b/examples/server.js index a46d31a..91e8424 100644 --- a/examples/server.js +++ b/examples/server.js @@ -1,6 +1,6 @@ var rpc = require('../src/jsonrpc'); -var server = rpc.Server.create({ +var server = rpc.Server.$create({ websocket: true }); diff --git a/examples/stream-client.js b/examples/stream-client.js index 190ea23..6553764 100644 --- a/examples/stream-client.js +++ b/examples/stream-client.js @@ -12,7 +12,7 @@ var rpc = require('../src/jsonrpc'); /* Connect to HTTP server */ -var client = rpc.Client.create(8088, 'localhost'); +var client = rpc.Client.$create(8088, 'localhost'); client.stream('listen', [], function (err, connection){ if (err) { @@ -32,7 +32,7 @@ client.stream('listen', [], function (err, connection){ /* Connect to Raw socket server */ -var socketClient = rpc.Client.create(8089, 'localhost'); +var socketClient = rpc.Client.$create(8089, 'localhost'); socketClient.connectSocket(function (err, conn){ if (err) { diff --git a/examples/stream-server.js b/examples/stream-server.js index 2d5439f..5cf0c93 100644 --- a/examples/stream-server.js +++ b/examples/stream-server.js @@ -1,7 +1,7 @@ var rpc = require('../src/jsonrpc'); var events = require('events'); -var server = rpc.Server.create(); +var server = rpc.Server.$create(); server.on('error', function (err){ console.log(err.toString()); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..0eb2eee --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1437 @@ +{ + "name": "json-rpc2", + "version": "2.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/node": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.0.tgz", + "integrity": "sha512-WE4IOAC6r/yBZss1oQGM5zs2D7RuKR6Q+w+X2SouPofnWn+LbCqClRyhO3ZE7Ix8nmFgo/oVuuE01cJT2XB13A==", + "dev": true + }, + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true, + "optional": true + }, + "ansi-colors": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz", + "integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==", + "dev": true + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "better-curry": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/better-curry/-/better-curry-1.6.0.tgz", + "integrity": "sha1-OPcWskyM7geiYqvEHCLDFOIOOGk=" + }, + "binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "chokidar": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz", + "integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.1", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.2.0" + } + }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "^7.1.1" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, + "requires": { + "date-now": "^0.1.4" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", + "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "dev": true + }, + "entities": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", + "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "dev": true + } + } + }, + "domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, + "requires": { + "domelementtype": "1" + } + }, + "domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "dev": true, + "requires": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + }, + "es-abstract": { + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz", + "integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.1.5", + "is-regex": "^1.0.5", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimleft": "^2.1.1", + "string.prototype.trimright": "^2.1.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5class": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es5class/-/es5class-2.3.1.tgz", + "integrity": "sha1-QsXBipAWvLDbKKTTQOu4MfVdG2Y=", + "requires": { + "better-curry": "1.x.x" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "requires": { + "esprima": "^2.7.1", + "estraverse": "^1.9.1", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.2.0" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expect.js": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/expect.js/-/expect.js-0.3.1.tgz", + "integrity": "sha1-sKWaDS7/VDdUTr8M6qYBWEHQm1s=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "faye-websocket": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz", + "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz", + "integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==", + "dev": true, + "requires": { + "is-buffer": "~2.0.3" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true + }, + "handlebars": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "dev": true, + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "requires": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + } + }, + "http-parser-js": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", + "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-buffer": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz", + "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==", + "dev": true + }, + "is-callable": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", + "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "dev": true, + "requires": { + "abbrev": "1.0.x", + "async": "1.x", + "escodegen": "1.8.x", + "esprima": "2.7.x", + "glob": "^5.0.15", + "handlebars": "^4.0.1", + "js-yaml": "3.x", + "mkdirp": "0.5.x", + "nopt": "3.x", + "once": "1.x", + "resolve": "1.1.x", + "supports-color": "^3.1.0", + "which": "^1.1.1", + "wordwrap": "^1.0.0" + } + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } + } + }, + "jshint": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.11.0.tgz", + "integrity": "sha512-ooaD/hrBPhu35xXW4gn+o3SOuzht73gdBuffgJzrZBJZPGgGiiTvJEgTyxFvBO2nz0+X1G6etF8SzUODTlLY6Q==", + "dev": true, + "requires": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.11", + "minimatch": "~3.0.2", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz", + "integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==", + "dev": true, + "requires": { + "ansi-colors": "3.2.3", + "browser-stdout": "1.3.1", + "chokidar": "3.3.0", + "debug": "3.2.6", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "find-up": "3.0.0", + "glob": "7.1.3", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "3.13.1", + "log-symbols": "3.0.0", + "minimatch": "3.0.4", + "mkdirp": "0.5.3", + "ms": "2.1.1", + "node-environment-flags": "1.0.6", + "object.assign": "4.1.0", + "strip-json-comments": "2.0.1", + "supports-color": "6.0.0", + "which": "1.3.1", + "wide-align": "1.1.3", + "yargs": "13.3.2", + "yargs-parser": "13.1.2", + "yargs-unparser": "1.6.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz", + "integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "node-environment-flags": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz", + "integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==", + "dev": true, + "requires": { + "object.getownpropertydescriptors": "^2.0.3", + "semver": "^5.7.0" + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-inspect": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", + "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", + "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "readdirp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz", + "integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==", + "dev": true, + "requires": { + "picomatch": "^2.0.4" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string.prototype.trimleft": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz", + "integrity": "sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimstart": "^1.0.0" + } + }, + "string.prototype.trimright": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz", + "integrity": "sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5", + "string.prototype.trimend": "^1.0.0" + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + }, + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "uglify-js": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.9.1.tgz", + "integrity": "sha512-JUPoL1jHsc9fOjVFHdQIhqEEJsQvfKDjlubcCilu8U26uZ73qOg8VsN8O1jbuei44ZPlwL7kmbAdM4tzaUvqnA==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.3" + } + }, + "websocket-driver": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", + "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "requires": { + "http-parser-js": ">=0.4.0 <0.4.11", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", + "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yargs-unparser": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz", + "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==", + "dev": true, + "requires": { + "flat": "^4.1.0", + "lodash": "^4.17.15", + "yargs": "^13.3.0" + } + } + } +} diff --git a/package.json b/package.json index 4859627..393c228 100644 --- a/package.json +++ b/package.json @@ -1,51 +1,65 @@ -{ - "name": "json-rpc2", - "version": "0.4.3", - "description": "JSON-RPC 2.0 server and client library, with HTTP, TCP and Websocket endpoints", - "main": "./src/jsonrpc.js", - "keywords": [ - "json", - "rpc", - "rpc2", - "json-rpc", - "json-rpc2", - "jsonrpc", - "jsonrpc2", - "server", - "client", - "tcp", - "websocket", - "http" - ], - "author": "Eric Florenzano (eflorenzano.com)", - "dependencies": { - "jsonparse": "*", - "debug": "*", - "lodash": "*", - "es5class": "*", - "faye-websocket": "*", - "eventemitter3": "*" - }, - "engines": { - "node": "0.8.x || 0.10.x" - }, - "contributors": [ - "Bill Casarin (jb55.com)", - "Stefan Thomas (justmoon.net)", - "Paulo Cesar (github.com/pocesar)" - ], - "repository": { - "type": "git", - "url": "git://github.com/pocesar/node-jsonrpc2.git" - }, - "devDependencies": { - "mocha": "*", - "expect.js": "*", - "jshint": "*", - "istanbul": "*" - }, - "scripts": { - "test": "jshint examples src test && mocha test/*.js", - "coverage": "node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- -t 5000 test/jsonrpc-test.js" - } -} +{ + "name": "json-rpc2", + "version": "2.0.0", + "description": "JSON-RPC 2.0 server and client library, with HTTP, TCP and Websocket endpoints", + "main": "./src/jsonrpc.js", + "keywords": [ + "json", + "rpc", + "rpc2", + "json-rpc", + "json-rpc2", + "jsonrpc", + "jsonrpc2", + "server", + "client", + "tcp", + "websocket", + "http" + ], + "license": "MIT", + "author": { + "name": "Eric Florenzano", + "url": "eflorenzano.com" + }, + "maintainers": [ + { + "name": "Paulo Cesar", + "url": "https://github.com/pocesar" + } + ], + "dependencies": { + "jsonparse": "^1.3.1", + "debug": "^4.1.1", + "lodash": "^4.17.15", + "es5class": "^2.3.1", + "faye-websocket": "^0.11.3", + "object-assign": "^4.1.1" + }, + "engines": { + "node": ">= 10" + }, + "contributors": [ + "Bill Casarin (jb55.com)", + "Stefan Thomas (justmoon.net)", + "Paulo Cesar (github.com/pocesar)" + ], + "repository": { + "type": "git", + "url": "git://github.com/pocesar/node-jsonrpc2.git" + }, + "bugs": { + "url": "https://github.com/pocesar/node-jsonrpc2/issues" + }, + "devDependencies": { + "mocha": "^7.1.1", + "expect.js": "^0.3.1", + "jshint": "^2.11.0", + "istanbul": "^0.4.5", + "@types/node": "^13.13.0" + }, + "scripts": { + "test": "jshint examples src test && mocha test/jsonrpc-test.js", + "coverage": "node ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- -t 5000 test/jsonrpc-test.js" + } +} diff --git a/src/client.js b/src/client.js index d36be61..61ef087 100644 --- a/src/client.js +++ b/src/client.js @@ -4,6 +4,7 @@ module.exports = function (classes){ var net = require('net'), http = require('http'), + https = require('https'), WebSocket = classes.Websocket, JsonParser = require('jsonparse'), EventEmitter = classes.EventEmitter, @@ -15,17 +16,18 @@ module.exports = function (classes){ * JSON-RPC Client. */ Client = Endpoint.$define('Client', { - construct : function (port, host, user, password){ - this.$super(); + construct : function ($super, port, host, user, password){ + $super(); this.port = port; this.host = host; this.user = user; this.password = password; + this.on('error', () => {}); }, _authHeader: function(headers){ if (this.user && this.password) { - var buff = new Buffer(this.user + ':' + this.password).toString('base64'); + var buff = Buffer.from(this.user + ':' + this.password).toString('base64'); headers['Authorization'] = 'Basic ' + buff; } }, @@ -68,8 +70,16 @@ module.exports = function (classes){ method : 'POST', headers : headers }; + var request; + if(opts.https === true) { + if(opts.rejectUnauthorized !== undefined) { + options.rejectUnauthorized = opts.rejectUnauthorized; + } + request = https.request(options); + } else { + request = http.request(options); + } - var request = http.request(options); // Report errors from the http client. This also prevents crashes since // an exception is thrown if we don't handle this event. diff --git a/src/connection.js b/src/connection.js index a333205..75cc8d1 100644 --- a/src/connection.js +++ b/src/connection.js @@ -5,15 +5,15 @@ module.exports = function (classes){ _ = classes._, EventEmitter = classes.EventEmitter, Connection = EventEmitter.$define('Connection', { - construct: function (ep){ - this.$super(); + construct: function ($super, ep){ + $super(); this.endpoint = ep; this.callbacks = {}; this.latestId = 0; // Default error handler (prevents ''uncaught error event'') - this.on('error', function (){ }); + this.on('error', () => { }); }, /** * Make a standard RPC call to the other endpoint. @@ -62,7 +62,9 @@ module.exports = function (classes){ */ stream: function (onend){ if (_.isFunction(onend)) { - this.on('end', onend); + this.on('end', function(){ + onend(); + }); } }, @@ -85,9 +87,7 @@ module.exports = function (classes){ // Are we in the server? this.endpoint.handleCall(msg, this, function handleCall(err, result){ if (err) { - if (self.listeners('error').length) { - self.emit('error', err); - } + self.emit('error', err); EventEmitter.trace('-->', 'Failure ' + (EventEmitter.hasId(msg) ? '(id ' + msg.id + ')' : '') + ': ' + diff --git a/src/endpoint.js b/src/endpoint.js index 024aba0..13d6822 100644 --- a/src/endpoint.js +++ b/src/endpoint.js @@ -11,13 +11,14 @@ module.exports = function (classes){ * Has the ability to register RPC events and expose RPC methods. */ Endpoint = EventEmitter.$define('Endpoint', { - construct : function (){ - this.$super(); + construct : function ($super){ + $super(); this.functions = {}; this.scopes = {}; this.defaultScope = this; this.exposeModule = this.expose; + this.on('error', () => { }); }, /** * Define a callable method on this RPC endpoint @@ -53,7 +54,7 @@ module.exports = function (classes){ }, handleCall: function (decoded, conn, callback){ EventEmitter.trace('<--', 'Request (id ' + decoded.id + '): ' + - decoded.method + '(' + decoded.params.join(', ') + ')'); + decoded.method + '(' + JSON.stringify(decoded.params) + ')'); if (!this.functions.hasOwnProperty(decoded.method)) { callback(new Error.MethodNotFound('Unknown RPC call "' + decoded.method + '"')); @@ -74,4 +75,4 @@ module.exports = function (classes){ }); return Endpoint; -}; \ No newline at end of file +}; diff --git a/src/error.js b/src/error.js index 5209fc2..9b92d5e 100644 --- a/src/error.js +++ b/src/error.js @@ -7,15 +7,17 @@ module.exports = function (classes){ var Errors = {}; Errors.AbstractError = classes.ES5Class.$define('AbstractError', { - construct: function(message){ - this.name = this.$class.$className; - this.message = message || this.$class.$className; + construct: function(message, extra){ + this.name = this.$className; + this.extra = extra || {}; + this.message = message || this.$className; + Error.captureStackTrace(this, this.$class); }, toString: function(){ return this.message; } - }).$implement(Error, true); + }).$inherit(Error, []); Errors.ParseError = Errors.AbstractError.$define('ParseError', { code: -32700 diff --git a/src/event-emitter.js b/src/event-emitter.js index 40ba3b7..537472c 100644 --- a/src/event-emitter.js +++ b/src/event-emitter.js @@ -13,14 +13,19 @@ module.exports = function (classes){ return msg; }, /** - * Check if current request has an integer id + * Check if current request has an id adn it is of type integer (non fractional) or string. + * * @param {Object} request * @return {Boolean} */ - hasId : function (request){ - return request && typeof request['id'] !== 'undefined' && /^\-?\d+$/.test(request['id']); + hasId : function (request) { + return request && typeof request['id'] !== 'undefined' && + ( + (typeof(request['id']) === 'number' && /^\-?\d+$/.test(request['id'])) || + (typeof(request['id']) === 'string') || (request['id'] === null) + ); } - }).$implement(require('eventemitter3').EventEmitter, true); + }).$inherit(require('events').EventEmitter, []); return EventEmitter; }; diff --git a/src/http-server-connection.js b/src/http-server-connection.js index 58901c6..69283ea 100644 --- a/src/http-server-connection.js +++ b/src/http-server-connection.js @@ -4,16 +4,20 @@ module.exports = function (classes){ var Connection = classes.Connection, HttpServerConnection = Connection.$define('HttpServerConnection', { - construct: function (server, req, res){ + construct: function ($super, server, req, res){ var self = this; - this.$super(server); + $super(server); this.req = req; this.res = res; this.isStreaming = false; - this.res.connection.on('end', function responseEnd(){ + this.res.on('finish', function responseEnd(){ + self.emit('end'); + }); + + this.res.on('close', function responseEnd(){ self.emit('end'); }); }, @@ -21,8 +25,8 @@ module.exports = function (classes){ /** * Can be called before the response callback to keep the connection open. */ - stream: function (onend){ - this.$super(onend); + stream: function ($super, onend){ + $super(onend); this.isStreaming = true; }, diff --git a/src/server.js b/src/server.js index ad8dba0..796e231 100644 --- a/src/server.js +++ b/src/server.js @@ -4,7 +4,7 @@ module.exports = function (classes) { var net = require('net'), http = require('http'), - extend = require('util')._extend, + extend = require('object-assign'), JsonParser = require('jsonparse'), UNAUTHORIZED = 'Unauthorized', @@ -19,13 +19,14 @@ module.exports = function (classes) { * JSON-RPC Server. */ Server = Endpoint.$define('Server', { - construct: function (opts) { - this.$super(); + construct: function ($super, opts) { + $super(); this.opts = opts || {}; this.opts.type = typeof this.opts.type !== 'undefined' ? this.opts.type : 'http'; this.opts.headers = this.opts.headers || {}; this.opts.websocket = typeof this.opts.websocket !== 'undefined' ? this.opts.websocket : true; + this.on('error', () => {}); }, _checkAuth: function (req, res) { var self = this; @@ -34,7 +35,7 @@ module.exports = function (classes) { var authHeader = req.headers['authorization'] || '', // get the header authToken = authHeader.split(/\s+/).pop() || '', // get the token - auth = new Buffer(authToken, 'base64').toString(), // base64 -> string + auth = Buffer.from(authToken, 'base64').toString(), // base64 -> string parts = auth.split(/:/), // split on colon username = parts[0], password = parts[1]; @@ -116,6 +117,18 @@ module.exports = function (classes) { */ handleHttp: function (req, res) { var buffer = '', self = this; + var headers; + + if (req.method === 'OPTIONS') { + headers = { + 'Content-Length': 0, + 'Access-Control-Allow-Headers': 'Accept, Authorization, Content-Type' + }; + headers = extend({}, headers, self.opts.headers); + res.writeHead(200, headers); + res.end(); + return; + } if (!self._checkAuth(req, res)) { return; @@ -141,22 +154,34 @@ module.exports = function (classes) { // Check for the required fields, and if they aren't there, then // dispatch to the handleHttpError function. - if (!(decoded.method && decoded.params && decoded.id)) { + if (!decoded.method || !decoded.params) { Endpoint.trace('-->', 'Response (invalid request)'); Server.handleHttpError(req, res, new Error.InvalidRequest(INVALID_REQUEST), self.opts.headers); return; } var reply = function reply(json) { - var encoded = JSON.stringify(json); + var encoded; + headers = { + 'Content-Type': 'application/json' + }; + + if (json) { + encoded = JSON.stringify(json); + headers['Content-Length'] = Buffer.byteLength(encoded, 'utf-8'); + } else { + encoded = ''; + headers['Content-Length'] = 0; + } + + headers = extend({}, headers, self.opts.headers); if (!conn.isStreaming) { - res.writeHead(200, extend(self.opts.headers, {'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(encoded, 'utf-8')})); + res.writeHead(200, headers); res.write(encoded); res.end(); } else { - res.writeHead(200, extend(self.opts.headers, {'Content-Type': 'application/json'})); + res.writeHead(200, headers); res.write(encoded); // Keep connection open } @@ -170,10 +195,13 @@ module.exports = function (classes) { Endpoint.trace('-->', 'Failure (id ' + decoded.id + '): ' + (err.stack ? err.stack : err.toString())); + result = null; + if (!(err instanceof Error.AbstractError)) { err = new Error.InternalError(err.toString()); } + response = { 'jsonrpc': '2.0', 'error': {code: err.code, message: err.message } @@ -182,19 +210,22 @@ module.exports = function (classes) { } else { Endpoint.trace('-->', 'Response (id ' + decoded.id + '): ' + JSON.stringify(result)); + response = { 'jsonrpc': '2.0', - 'result': result || null + 'result': typeof(result) === 'undefined' ? null : result }; } + // Don't return a message if it doesn't have an ID if (Endpoint.hasId(decoded)) { response.id = decoded.id; reply(response); + } else { + reply(); } }; - var conn = new classes.HttpServerConnection(self, req, res); self.handleCall(decoded, conn, callback); @@ -347,10 +378,12 @@ module.exports = function (classes) { 'id': null }); custom_headers = custom_headers || {}; - var headers = extend(custom_headers, {'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(message), - 'Access-Control-Allow-Headers': 'Content-Type', - 'Allow': 'POST'}); + var headers = extend({ + 'Content-Type': 'application/json', + 'Content-Length': Buffer.byteLength(message), + 'Access-Control-Allow-Headers': 'Content-Type', + 'Allow': 'POST' + }, custom_headers); /*if (code === 401) { headers['WWW-Authenticate'] = 'Basic realm=' + 'JSON-RPC' + ''; diff --git a/src/socket-connection.js b/src/socket-connection.js index 48ea62f..0df2f18 100644 --- a/src/socket-connection.js +++ b/src/socket-connection.js @@ -11,10 +11,10 @@ module.exports = function (classes){ * representing both the server and client perspective. */ SocketConnection = Connection.$define('SocketConnection', { - construct: function (endpoint, conn){ + construct: function ($super, endpoint, conn){ var self = this; - self.$super(endpoint); + $super(endpoint); self.conn = conn; self.autoReconnect = true; @@ -36,7 +36,7 @@ module.exports = function (classes){ self.emit('close', hadError); if ( - self.endpoint.$class.$className === 'Client' && + self.endpoint.$className === 'Client' && self.autoReconnect && !self.ended ) { if (hadError) { @@ -66,7 +66,7 @@ module.exports = function (classes){ reconnect: function (){ this.ended = false; - if (this.endpoint.$class.$className === 'Client') { + if (this.endpoint.$className === 'Client') { this.conn.connect(this.endpoint.port, this.endpoint.host); } else { throw new Error('Cannot reconnect a connection from the server-side.'); diff --git a/src/websocket-connection.js b/src/websocket-connection.js index f91e9ce..0962c33 100644 --- a/src/websocket-connection.js +++ b/src/websocket-connection.js @@ -11,10 +11,10 @@ module.exports = function (classes){ * representing both the server and client perspective. */ WebSocketConnection = Connection.$define('WebSocketConnection', { - construct: function (endpoint, conn){ + construct: function ($super, endpoint, conn){ var self = this; - self.$super(endpoint); + $super(endpoint); self.conn = conn; self.ended = false; diff --git a/test/jsonrpc-test.js b/test/jsonrpc-test.js index 2f3b784..966a1f3 100644 --- a/test/jsonrpc-test.js +++ b/test/jsonrpc-test.js @@ -7,12 +7,12 @@ var module.exports = { beforeEach : function (){ - server = rpc.Server.create(); + server = rpc.Server.$create(); // MOCK REQUEST/RESPONSE OBJECTS MockRequest = rpc.EventEmitter.$define('MockRequest', { - construct: function(method){ - this.$super(); + construct: function($super, method){ + $super(); this.method = method; } }); @@ -44,8 +44,8 @@ module.exports = { server.expose('javascript_error', javascript_error); MockResponse = rpc.EventEmitter.$define('MockResponse', { - construct: function(){ - this.$super(); + construct: function($super){ + $super(); this.writeHead = this.sendHeader = function (httpCode){ this.httpCode = httpCode; @@ -76,9 +76,9 @@ module.exports = { req.emit('data', testJSON); req.emit('end'); var decoded = JSON.parse(res.httpBody); - expect(decoded.id).to.equal(null); - expect(decoded.error.message).to.equal('Invalid Request'); - expect(decoded.error.code).to.equal(-32600); + expect(decoded.id).equal(null); + expect(decoded.error.message).equal('Invalid Request'); + expect(decoded.error.code).equal(-32600); done(); }; }, @@ -91,12 +91,12 @@ module.exports = { }, 'json-rpc2': { 'Server expose': function (){ - expect(server.functions.echo).to.eql(echo); + expect(server.functions.echo).eql(echo); }, 'Server exposeModule': function (){ server.exposeModule('test', TestModule); - expect(server.functions['test.foo']).to.eql(TestModule.foo); + expect(server.functions['test.foo']).eql(TestModule.foo); }, 'GET Server handle NonPOST': function (){ @@ -104,9 +104,9 @@ module.exports = { var res = new MockResponse(); server.handleHttp(req, res); var decoded = JSON.parse(res.httpBody); - expect(decoded.id).to.equal(null); - expect(decoded.error.message).to.equal('Invalid Request'); - expect(decoded.error.code).to.equal(-32600); + expect(decoded.id).equal(null); + expect(decoded.error.message).equal('Invalid Request'); + expect(decoded.error.code).equal(-32600); }, 'Method throw an error' : function() { var req = new MockRequest('POST'); @@ -115,9 +115,9 @@ module.exports = { req.emit('data', '{ "method": "throw_error", "params": [], "id": 1 }'); req.emit('end'); var decoded = JSON.parse(res.httpBody); - expect(decoded.id).to.equal(1); - expect(decoded.error.message).to.equal('InternalError'); - expect(decoded.error.code).to.equal(-32603); + expect(decoded.id).equal(1); + expect(decoded.error.message).equal('InternalError'); + expect(decoded.error.code).equal(-32603); }, 'Method return an rpc error' : function() { var req = new MockRequest('POST'); @@ -126,9 +126,9 @@ module.exports = { req.emit('data', '{ "method": "json_rpc_error", "params": [], "id": 1 }'); req.emit('end'); var decoded = JSON.parse(res.httpBody); - expect(decoded.id).to.equal(1); - expect(decoded.error.message).to.equal('InternalError'); - expect(decoded.error.code).to.equal(-32603); + expect(decoded.id).equal(1); + expect(decoded.error.message).equal('InternalError'); + expect(decoded.error.code).equal(-32603); }, // text_error javascript_error @@ -142,11 +142,6 @@ module.exports = { testBadRequest(testJSON, done); }, - 'Missing object attribute (id)': function (done){ - var testJSON = '{ "method": "echo", "params": ["Hello, World!"] }'; - testBadRequest(testJSON, done); - }, - 'Unregistered method': function (){ var testJSON = '{ "method": "notRegistered", "params": ["Hello, World!"], "id": 1 }'; var req = new MockRequest('POST'); @@ -156,11 +151,11 @@ module.exports = { } catch (e) {} req.emit('data', testJSON); req.emit('end'); - expect(res.httpCode).to.equal(200); + expect(res.httpCode).equal(200); var decoded = JSON.parse(res.httpBody); - expect(decoded.id).to.equal(1); - expect(decoded.error.message).to.equal('Unknown RPC call "notRegistered"'); - expect(decoded.error.code).to.equal(-32601); + expect(decoded.id).equal(1); + expect(decoded.error.message).equal('Unknown RPC call "notRegistered"'); + expect(decoded.error.code).equal(-32601); }, // VALID REQUEST @@ -172,11 +167,39 @@ module.exports = { server.handleHttp(req, res); req.emit('data', testJSON); req.emit('end'); - expect(res.httpCode).to.equal(200); + expect(res.httpCode).equal(200); var decoded = JSON.parse(res.httpBody); - expect(decoded.id).to.equal(1); - expect(decoded.error).to.equal(undefined); - expect(decoded.result).to.equal('Hello, World!'); + expect(decoded.id).equal(1); + expect(decoded.error).equal(undefined); + expect(decoded.result).equal('Hello, World!'); + }, + + 'Simple synchronous echo with id as null': function (){ + var testJSON = '{ "method": "echo", "params": ["Hello, World!"], "id": null }'; + var req = new MockRequest('POST'); + var res = new MockResponse(); + server.handleHttp(req, res); + req.emit('data', testJSON); + req.emit('end'); + expect(res.httpCode).equal(200); + var decoded = JSON.parse(res.httpBody); + expect(decoded.id).equal(null); + expect(decoded.error).equal(undefined); + expect(decoded.result).equal('Hello, World!'); + }, + + 'Simple synchronous echo with string as id': function (){ + var testJSON = '{ "method": "echo", "params": ["Hello, World!"], "id": "test" }'; + var req = new MockRequest('POST'); + var res = new MockResponse(); + server.handleHttp(req, res); + req.emit('data', testJSON); + req.emit('end'); + expect(res.httpCode).equal(200); + var decoded = JSON.parse(res.httpBody); + expect(decoded.id).equal('test'); + expect(decoded.error).equal(undefined); + expect(decoded.result).equal('Hello, World!'); }, 'Using promise': function (){ @@ -197,15 +220,15 @@ module.exports = { // would be finished. However, this function is smarter and only completes // when the promise completes. Therefore, we should not have a response // yet. - expect(res.httpCode).to.not.be.ok(); + expect(res.httpCode).be(undefined); // We can force the promise to emit a success code, with a message. callbackRef(null, 'Hello, World!'); // Aha, now that the promise has finished, our request has finished as well. - expect(res.httpCode).to.equal(200); + expect(res.httpCode).equal(200); var decoded = JSON.parse(res.httpBody); - expect(decoded.id).to.equal(1); - expect(decoded.error).to.equal(undefined); - expect(decoded.result).to.equal('Hello, World!'); + expect(decoded.id).equal(1); + expect(decoded.error).equal(undefined); + expect(decoded.result).equal('Hello, World!'); }, 'Triggering an errback': function (){ @@ -219,16 +242,28 @@ module.exports = { server.handleHttp(req, res); req.emit('data', testJSON); req.emit('end'); - expect(res.httpCode).to.not.be.ok(); + expect(res.httpCode).be(undefined); // This time, unlike the above test, we trigger an error and expect to see // it in the error attribute of the object returned. callbackRef('This is an error'); - expect(res.httpCode).to.equal(200); + expect(res.httpCode).equal(200); var decoded = JSON.parse(res.httpBody); - expect(decoded.id).to.equal(1); - expect(decoded.error.message).to.equal('This is an error'); - expect(decoded.error.code).to.equal(-32603); - expect(decoded.result).to.equal(undefined); + expect(decoded.id).equal(1); + expect(decoded.error.message).equal('This is an error'); + expect(decoded.error.code).equal(-32603); + expect(decoded.result).equal(undefined); + }, + 'Notification request': function () { + var testJSON = '{ "method": "notify_test", "params": ["Hello, World!"] }'; + var req = new MockRequest('POST'); + var res = new MockResponse(); + server.handleHttp(req, res); + req.emit('data', testJSON); + req.emit('end'); + // although it shouldn't return a response, we are dealing with HTTP, that MUST + // return something, in most cases, 0 length body + expect(res.httpCode).equal(200); + expect(res.httpBody).equal(''); } } }; diff --git a/test/mocha.opts b/test/mocha.opts deleted file mode 100644 index aa9bf38..0000000 --- a/test/mocha.opts +++ /dev/null @@ -1,4 +0,0 @@ ---reporter list ---ui exports ---check-leaks ---debug-brk \ No newline at end of file