diff --git a/.gitignore b/.gitignore index 3adea5b..1d9d24f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,54 +1,8 @@ -###Node### - -# Logs -logs -*.log - -# Runtime data -pids -*.pid -*.seed - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul coverage - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directory -# Commenting this out is preferred by some people, see -# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- node_modules - -# Users Environment Variables -.lock-wscript - - -###OSX### - .DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear on external disk -.Spotlight-V100 -.Trashes - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk \ No newline at end of file +npm-debug.log +.idea +out +.nyc_output +test/tmp diff --git a/.npmignore b/.npmignore index 7c948d3..225554a 100644 --- a/.npmignore +++ b/.npmignore @@ -1,63 +1,12 @@ -###Node### - -# Logs -logs -*.log - -# Runtime data -pids -*.pid -*.seed - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul coverage - -# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release - -# Dependency directory -# Commenting this out is preferred by some people, see -# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- node_modules - -# Users Environment Variables -.lock-wscript - - -###OSX### - .DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - - -# Thumbnails -._* - -# Files that might appear on external disk -.Spotlight-V100 -.Trashes - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -# npm specific - +npm-debug.log test -.cz.json .travis.yml .editorconfig -bin \ No newline at end of file +benchmarks +.idea +bin +out +.nyc_output diff --git a/.travis.yml b/.travis.yml index 499a854..9d4fb63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,10 @@ language: node_js node_js: - node -- 5.3.0 -- 4.0.0 +- 7.0.0 sudo: false -services: -- redis-server install: -- npm install --no-optional +- npm install notifications: slack: secure: m91zkX2cLVDRDMBAUnR1d+hbZqtSHXLkuPencHadhJ3C3wm53Box8U25co/goAmjnW5HNJ1SMSIg+DojtgDhqTbReSh5gSbU0uU8YaF8smbvmUv3b2Q8PRCA7f6hQiea+a8+jAb7BOvwh66dV4Al/1DJ2b4tCjPuVuxQ96Wll7Pnj1S7yW/Hb8fQlr9wc+INXUZOe8erFin+508r5h1L4Xv0N5ZmNw+Gqvn2kPJD8f/YBPpx0AeZdDssTL0IOcol1+cDtDzMw5PAkGnqwamtxhnsw+i8OW4avFt1GrRNlz3eci5Cb3NQGjHxJf+JIALvBeSqkOEFJIFGqwAXMctJ9q8/7XyXk7jVFUg5+0Z74HIkBwdtLwi/BTyXMZAgsnDjndmR9HsuBP7OSTJF5/V7HCJZAaO9shEgS8DwR78owv9Fr5er5m9IMI+EgSH3qtb8iuuQaPtflbk+cPD3nmYbDqmPwkSCXcXRfq3IxdcV9hkiaAw52AIqqhnAXJWZfL6+Ct32i2mtSaov9FYtp/G0xb4tjrUAsDUd/AGmMJNEBVoHtP7mKjrVQ35cEtFwJr/8SmZxGvOaJXPaLs43dhXKa2tAGl11wF02d+Rz1HhbOoq9pJvJuqkLAVvRdBHUJrB4/hnTta5B0W5pe3mIgLw3AmOpk+s/H4hAP4Hp0gOWlPA= diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..c0f2fec --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,22 @@ +environment: + matrix: + - nodejs_version: 'Stable' + - nodejs_version: '7' + +init: + git config --global core.autocrlf true + +install: + - ps: Install-Product node $env:nodejs_version + - npm install + +test_script: + - node --version + - npm --version + - npm run test:win + +build: off +clone_depth: 1 + +matrix: + fast_finish: true diff --git a/bin/coverage.js b/bin/coverage.js deleted file mode 100644 index 258b08f..0000000 --- a/bin/coverage.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict' - -const shell = require('shelljs') -const nodeVersion = process.version -let proxiesFlag = null - -if (nodeVersion < 'v6.5.0') { - proxiesFlag = '--harmony_proxies' -} - -shell.exec('npm run lint') -shell.exec(`node ${proxiesFlag} ./node_modules/.bin/istanbul cover _mocha test --bail`) \ No newline at end of file diff --git a/bin/index.js b/bin/index.js new file mode 100644 index 0000000..b53ef79 --- /dev/null +++ b/bin/index.js @@ -0,0 +1,40 @@ +'use strict' + +/* + * adonis-framework + * + * (c) Harminder Virk + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. +*/ + +const semver = require('semver') +const { spawn } = require('child_process') +const spawnArgs = [] + +if (semver.lt(process.version, '8.0.0')) { + spawnArgs.push('--harmony-async-await') +} + +function local () { + spawnArgs.push('./node_modules/.bin/japa') + const tests = spawn('node', spawnArgs) + tests.stdout.on('data', (data) => process.stdout.write(data)) + tests.stderr.on('data', (data) => process.stderr.write(data)) + tests.on('close', (code) => process.exit(code)) +} + +function win () { + spawnArgs.push('./node_modules/japa-cli/index.js') + const tests = spawn('node', spawnArgs) + tests.stdout.on('data', (data) => process.stdout.write(data)) + tests.stderr.on('data', (data) => process.stderr.write(data)) + tests.on('close', (code) => process.exit(code)) +} + +if (process.argv.indexOf('--local') > -1) { + local() +} else if (process.argv.indexOf('--win') > -1) { + win() +} diff --git a/bin/test.js b/bin/test.js deleted file mode 100644 index 14ad745..0000000 --- a/bin/test.js +++ /dev/null @@ -1,12 +0,0 @@ -'use strict' - -const shell = require('shelljs') -const nodeVersion = process.version -let proxiesFlag = null - -if (nodeVersion < 'v6.5.0') { - proxiesFlag = '--harmony_proxies' -} - -shell.exec('npm run lint') -shell.exec(`node ${proxiesFlag} ./node_modules/.bin/istanbul cover _mocha --report lcovonly -- -R spec test && cat ./coverage/lcov.info | coveralls && rm -rf ./coverage`) \ No newline at end of file diff --git a/examples/redis.js b/examples/redis.js index 6169383..0dd8707 100644 --- a/examples/redis.js +++ b/examples/redis.js @@ -13,7 +13,6 @@ const Env = use('Env') module.exports = { - /* |-------------------------------------------------------------------------- | connection @@ -40,7 +39,6 @@ module.exports = { keyPrefix: '' }, - /* |-------------------------------------------------------------------------- | cluster config @@ -63,6 +61,4 @@ module.exports = { db: 0 }] } - - } diff --git a/lib/util.js b/lib/util.js deleted file mode 100644 index a33d06b..0000000 --- a/lib/util.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict' - -/** - * adonis-redis - * - * (c) Harminder Virk - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. -*/ - -const util = exports = module.exports = {} - -const toStr = Object.prototype.toString -const fnToStr = Function.prototype.toString -const isFnRegex = /^\s*(?:function)?\*/ - -util.isGenerator = function (method) { - const viaToStr = toStr.call(method) - const viaFnToStr = fnToStr.call(method) - return (viaToStr === '[object Function]' || viaToStr === '[object GeneratorFunction]') && isFnRegex.test(viaFnToStr) -} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..4a6ee2a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2806 @@ +{ + "name": "@adonisjs/redis", + "version": "1.0.1", + "lockfileVersion": 1, + "dependencies": { + "@adonisjs/fold": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@adonisjs/fold/-/fold-4.0.0.tgz", + "integrity": "sha512-IQj0Jr6vOVmkjJkcyHg/VxI5Dm6p8NeALHFIgJhkzNf9vekWPadX7flSnTindv32/bSwzRTFpYWsR/7PXc7urg==", + "dev": true, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "node-exceptions": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-exceptions/-/node-exceptions-2.0.2.tgz", + "integrity": "sha512-nILccFLvnaOBoKZZtWfZipn/hlThZOT6UJOLX6SA3yLMYPcvLTIF26PXx73sPnAg45p05iYFYw2jvayNHz4rDA==", + "dev": true + } + } + }, + "@adonisjs/sink": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@adonisjs/sink/-/sink-1.0.9.tgz", + "integrity": "sha512-YS+k2HOTJDQeKzgU+wEeR1foGCC9CAZ+nl2qrwJpKCUmGBw5rdiOBakq2/2pwTePqNVUXbjDNU8UG03NjfP1Fw==", + "dev": true, + "dependencies": { + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + } + } + }, + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true + }, + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true + }, + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array.prototype.find": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.0.4.tgz", + "integrity": "sha1-VWpcU2LAhkgyPdrrnenRS8GGTJA=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true + }, + "assertion-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.2.tgz", + "integrity": "sha1-E8pRXYYgbaC6xm6DTdOX2HWBCUw=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "babel-code-frame": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", + "integrity": "sha1-AnYgvuVnqIwyVhV05/0IAdMxGOQ=", + "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 + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true + }, + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "caller": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/caller/-/caller-1.0.1.tgz", + "integrity": "sha1-uFGGD3Dhlds9J3OVqhp+I+ow7PU=", + "dev": true + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true + }, + "chai": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-3.5.0.tgz", + "integrity": "sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true + }, + "circular-json": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.1.tgz", + "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=", + "dev": true + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true + }, + "cli-width": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.1.0.tgz", + "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=", + "dev": true + }, + "cluster-key-slot": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.0.8.tgz", + "integrity": "sha1-dlRVYIWmUzCTKi6LWXb44tCz5BQ=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": 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 + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "conventional-commit-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/conventional-commit-types/-/conventional-commit-types-2.2.0.tgz", + "integrity": "sha1-XblXOdbCEqy+e29lahG5QLqmiUY=", + "dev": true + }, + "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 + }, + "coveralls": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.13.1.tgz", + "integrity": "sha1-1wu5rMGDXsTwY/+drFQjwXsR8Xg=", + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true + }, + "cz-conventional-changelog": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cz-conventional-changelog/-/cz-conventional-changelog-2.0.0.tgz", + "integrity": "sha1-Val5r9/pXnAkh50qD1kkYwFwtTM=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=" + }, + "debug-log": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", + "dev": true + }, + "deep-eql": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", + "integrity": "sha1-71WKyrjeJSBs1xOQbXTlaTDrafI=", + "dev": true, + "dependencies": { + "type-detect": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz", + "integrity": "sha1-C6XsKohWQORw6k6FBZcZANrFiCI=", + "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.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true + }, + "deglob": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deglob/-/deglob-2.1.0.tgz", + "integrity": "sha1-TUSr4W7zLHebSXK9FBqAMlApoUo=", + "dev": true + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "dependencies": { + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "denque": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.1.1.tgz", + "integrity": "sha1-ECKcK4juwb0V/4LF/eNW5762254=" + }, + "doctrine": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", + "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true + }, + "es-abstract": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.7.0.tgz", + "integrity": "sha1-363ndOAb/Nl/lhgCmMRJyGI/uUw=", + "dev": true + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true + }, + "es5-ext": { + "version": "0.10.24", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.24.tgz", + "integrity": "sha1-pVh3yZJLwMjZvTwsvhdJWsFwmxQ=", + "dev": true + }, + "es6-iterator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", + "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", + "dev": true + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dev": true + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dev": true + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true + }, + "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 + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", + "dev": true + }, + "eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", + "dev": true + }, + "eslint-config-standard": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz", + "integrity": "sha1-wGHk0GbzedwXzVYsZOgZtN1FRZE=", + "dev": true + }, + "eslint-config-standard-jsx": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-4.0.1.tgz", + "integrity": "sha1-zU5GPQJo4tnnB/YfQvc/WzMzxkI=", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz", + "integrity": "sha1-Wt2BBujJKNssuiMrzZ76hG49oWw=", + "dev": true + }, + "eslint-module-utils": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz", + "integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==", + "dev": true + }, + "eslint-plugin-import": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.2.0.tgz", + "integrity": "sha1-crowb60wXWfEgWNIpGmaQimsi04=", + "dev": true, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true + } + } + }, + "eslint-plugin-node": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-4.2.3.tgz", + "integrity": "sha512-vIUQPuwbVYdz/CYnlTLsJrRy7iXHQjdEe5wz0XhhdTym3IInM/zZLlPf9nZ2mThsH0QcsieCOWs2vOeCy/22LQ==", + "dev": true + }, + "eslint-plugin-promise": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz", + "integrity": "sha1-ePu2/+BHIBYnVp6FpsU3OvKmj8o=", + "dev": true + }, + "eslint-plugin-react": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-6.10.3.tgz", + "integrity": "sha1-xUNb6wZ3ThLH2y9qut3L+QDNP3g=", + "dev": true, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true + } + } + }, + "eslint-plugin-standard": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz", + "integrity": "sha1-NNDJFbRe3G8BA5PH7vOCOwhWXPI=", + "dev": true + }, + "espree": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", + "integrity": "sha1-KRC1zNSc6JPC//+qtP2LOjG4I3Q=", + "dev": true, + "dependencies": { + "acorn": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", + "integrity": "sha512-vOk6uEMctu0vQrvuSqFdJyqj1Q0S5VTDL79qtjo+DhRr+1mmaD+tluFSCZqhvi/JUhXSzoZN2BhtstaPEeE8cw==", + "dev": true + } + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "dev": true + }, + "esrecurse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", + "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dev": true + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=", + "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 + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true + }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "dev": true + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true + }, + "flat-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", + "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", + "dev": true + }, + "flexbuffer": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flexbuffer/-/flexbuffer-0.0.6.tgz", + "integrity": "sha1-A5/fI/iCPkQMOPMnfm/vEXQhWzA=" + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.0.tgz", + "integrity": "sha1-FhdnFMgBeY5Ojyz391KUZ7tKV3E=", + "dev": true + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true + }, + "get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "dev": true + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true + }, + "ignore": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.3.tgz", + "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "dev": true + }, + "interpret": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz", + "integrity": "sha1-y8NcYu7uc/Gat7EKgBURQBr8D5A=", + "dev": true + }, + "ioredis": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-3.1.1.tgz", + "integrity": "sha1-zC8dMjK4yVzBUwRrzhaPK6oRhug=" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true + }, + "is-my-json-valid": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz", + "integrity": "sha1-8Hndm/2uZe4gOKrorLyGqxCeNpM=", + "dev": true + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true + }, + "is-path-inside": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true + }, + "is-resolvable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", + "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", + "dev": true + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "japa": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/japa/-/japa-1.0.3.tgz", + "integrity": "sha1-X47NxWDtJg5XPpRxJfVolnbwJN8=", + "dev": true, + "dependencies": { + "ms": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz", + "integrity": "sha1-cIFVpeROM/X9D8U+gdDUCpG+H/8=", + "dev": true + } + } + }, + "japa-cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/japa-cli/-/japa-cli-1.0.1.tgz", + "integrity": "sha1-CGcrxKIvh5IaWij54X+5N3OBcGA=", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", + "integrity": "sha1-bl/mfYsgXOTSL60Ft3geja3MSzA=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jsprim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "jsx-ast-utils": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz", + "integrity": "sha1-OGchPo3Xm/Ho8jAMDPwe+xgsDfE=", + "dev": true + }, + "lcov-parse": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", + "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "dev": true + }, + "left-pad": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.1.3.tgz", + "integrity": "sha1-YS9hwDPzqeCOk58crr7qQbbzGZo=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "dependencies": { + "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 + } + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + }, + "lodash.cond": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", + "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", + "dev": true + }, + "lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=", + "dev": true + }, + "log-driver": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", + "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=", + "dev": true + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "mime-db": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=", + "dev": true + }, + "mime-types": { + "version": "2.1.15", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-exceptions": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-exceptions/-/node-exceptions-2.0.2.tgz", + "integrity": "sha512-nILccFLvnaOBoKZZtWfZipn/hlThZOT6UJOLX6SA3yLMYPcvLTIF26PXx73sPnAg45p05iYFYw2jvayNHz4rDA==" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "nyc": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.0.3.tgz", + "integrity": "sha1-DCi8ZpqFFiFwm/eghQMDS+44ErY=", + "dev": true, + "dependencies": { + "align-text": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true, + "dev": true + }, + "append-transform": { + "version": "0.4.0", + "bundled": true, + "dev": true + }, + "archy": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "arr-diff": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "arr-flatten": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "async": { + "version": "1.5.2", + "bundled": true, + "dev": true + }, + "babel-code-frame": { + "version": "6.22.0", + "bundled": true, + "dev": true + }, + "babel-generator": { + "version": "6.25.0", + "bundled": true, + "dev": true + }, + "babel-messages": { + "version": "6.23.0", + "bundled": true, + "dev": true + }, + "babel-runtime": { + "version": "6.23.0", + "bundled": true, + "dev": true + }, + "babel-template": { + "version": "6.25.0", + "bundled": true, + "dev": true + }, + "babel-traverse": { + "version": "6.25.0", + "bundled": true, + "dev": true + }, + "babel-types": { + "version": "6.25.0", + "bundled": true, + "dev": true + }, + "babylon": { + "version": "6.17.4", + "bundled": true, + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "brace-expansion": { + "version": "1.1.8", + "bundled": true, + "dev": true + }, + "braces": { + "version": "1.8.5", + "bundled": true, + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "caching-transform": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true + }, + "center-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "dev": true + }, + "cliui": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "optional": true, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "commondir": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true + }, + "convert-source-map": { + "version": "1.5.0", + "bundled": true, + "dev": true + }, + "core-js": { + "version": "2.4.1", + "bundled": true, + "dev": true + }, + "cross-spawn": { + "version": "4.0.2", + "bundled": true, + "dev": true + }, + "debug": { + "version": "2.6.8", + "bundled": true, + "dev": true + }, + "debug-log": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "decamelize": { + "version": "1.2.0", + "bundled": true, + "dev": true + }, + "default-require-extensions": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "bundled": true, + "dev": true + }, + "error-ex": { + "version": "1.3.1", + "bundled": true, + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true, + "dev": true + }, + "execa": { + "version": "0.5.1", + "bundled": true, + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "bundled": true, + "dev": true + }, + "expand-range": { + "version": "1.8.2", + "bundled": true, + "dev": true + }, + "extglob": { + "version": "0.3.2", + "bundled": true, + "dev": true + }, + "filename-regex": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "fill-range": { + "version": "2.2.3", + "bundled": true, + "dev": true + }, + "find-cache-dir": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "for-in": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "for-own": { + "version": "0.1.5", + "bundled": true, + "dev": true + }, + "foreground-child": { + "version": "1.5.6", + "bundled": true, + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "get-caller-file": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "get-stream": { + "version": "2.3.1", + "bundled": true, + "dev": true + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "dev": true + }, + "glob-base": { + "version": "0.3.0", + "bundled": true, + "dev": true + }, + "glob-parent": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "globals": { + "version": "9.18.0", + "bundled": true, + "dev": true + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true, + "dev": true + }, + "handlebars": { + "version": "4.0.10", + "bundled": true, + "dev": true, + "dependencies": { + "source-map": { + "version": "0.4.4", + "bundled": true, + "dev": true + } + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "has-flag": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "hosted-git-info": { + "version": "2.4.2", + "bundled": true, + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true, + "dev": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true + }, + "invariant": { + "version": "2.2.2", + "bundled": true, + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "is-buffer": { + "version": "1.1.5", + "bundled": true, + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "bundled": true, + "dev": true + }, + "is-extendable": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "is-number": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "is-posix-bracket": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "bundled": true, + "dev": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "isobject": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "istanbul-lib-coverage": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "istanbul-lib-hook": { + "version": "1.0.7", + "bundled": true, + "dev": true + }, + "istanbul-lib-instrument": { + "version": "1.7.3", + "bundled": true, + "dev": true + }, + "istanbul-lib-report": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "dependencies": { + "supports-color": { + "version": "3.2.3", + "bundled": true, + "dev": true + } + } + }, + "istanbul-lib-source-maps": { + "version": "1.2.1", + "bundled": true, + "dev": true + }, + "istanbul-reports": { + "version": "1.1.1", + "bundled": true, + "dev": true + }, + "js-tokens": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "jsesc": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true + }, + "lazy-cache": { + "version": "1.0.4", + "bundled": true, + "dev": true, + "optional": true + }, + "lcid": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "load-json-file": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + }, + "lodash": { + "version": "4.17.4", + "bundled": true, + "dev": true + }, + "longest": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "bundled": true, + "dev": true + }, + "lru-cache": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "md5-hex": { + "version": "1.3.0", + "bundled": true, + "dev": true + }, + "md5-o-matic": { + "version": "0.1.1", + "bundled": true, + "dev": true + }, + "mem": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "merge-source-map": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "bundled": true, + "dev": true + }, + "mimic-fn": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true + }, + "ms": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "normalize-package-data": { + "version": "2.3.8", + "bundled": true, + "dev": true + }, + "normalize-path": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "npm-run-path": { + "version": "2.0.2", + "bundled": true, + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "object.omit": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true + }, + "optimist": { + "version": "0.6.1", + "bundled": true, + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "os-locale": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "p-limit": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "parse-glob": { + "version": "3.0.4", + "bundled": true, + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "path-key": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true, + "dev": true + }, + "path-type": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "pify": { + "version": "2.3.0", + "bundled": true, + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true, + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "dependencies": { + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true + } + } + }, + "preserve": { + "version": "0.2.0", + "bundled": true, + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "randomatic": { + "version": "1.1.7", + "bundled": true, + "dev": true, + "dependencies": { + "is-number": { + "version": "3.0.0", + "bundled": true, + "dev": true, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "bundled": true, + "dev": true + } + } + }, + "kind-of": { + "version": "4.0.0", + "bundled": true, + "dev": true + } + } + }, + "read-pkg": { + "version": "1.1.0", + "bundled": true, + "dev": true + }, + "read-pkg-up": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "dependencies": { + "find-up": { + "version": "1.1.2", + "bundled": true, + "dev": true + } + } + }, + "regenerator-runtime": { + "version": "0.10.5", + "bundled": true, + "dev": true + }, + "regex-cache": { + "version": "0.4.3", + "bundled": true, + "dev": true + }, + "remove-trailing-separator": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "bundled": true, + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "bundled": true, + "dev": true + }, + "repeating": { + "version": "2.0.1", + "bundled": true, + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "bundled": true, + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "resolve-from": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "right-align": { + "version": "0.1.3", + "bundled": true, + "dev": true, + "optional": true + }, + "rimraf": { + "version": "2.6.1", + "bundled": true, + "dev": true + }, + "semver": { + "version": "5.3.0", + "bundled": true, + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true + }, + "slide": { + "version": "1.1.6", + "bundled": true, + "dev": true + }, + "source-map": { + "version": "0.5.6", + "bundled": true, + "dev": true + }, + "spawn-wrap": { + "version": "1.3.7", + "bundled": true, + "dev": true + }, + "spdx-correct": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "spdx-expression-parse": { + "version": "1.0.4", + "bundled": true, + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "bundled": true, + "dev": true + }, + "string-width": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true, + "dev": true + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "strip-bom": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "bundled": true, + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "test-exclude": { + "version": "4.1.1", + "bundled": true, + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "bundled": true, + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "bundled": true, + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "bundled": true, + "dev": true, + "optional": true, + "dependencies": { + "yargs": { + "version": "3.10.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "bundled": true, + "dev": true + }, + "which": { + "version": "1.2.14", + "bundled": true, + "dev": true + }, + "which-module": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "window-size": { + "version": "0.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "0.0.3", + "bundled": true, + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "bundled": true, + "dev": true, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true + }, + "write-file-atomic": { + "version": "1.3.4", + "bundled": true, + "dev": true + }, + "y18n": { + "version": "3.2.1", + "bundled": true, + "dev": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true, + "dev": true + }, + "yargs": { + "version": "8.0.2", + "bundled": true, + "dev": true, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "bundled": true, + "dev": true + }, + "cliui": { + "version": "3.2.0", + "bundled": true, + "dev": true, + "dependencies": { + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true + } + } + }, + "load-json-file": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "path-type": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "read-pkg-up": { + "version": "2.0.0", + "bundled": true, + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "bundled": true, + "dev": true + }, + "yargs-parser": { + "version": "7.0.0", + "bundled": true, + "dev": true + } + } + }, + "yargs-parser": { + "version": "5.0.0", + "bundled": true, + "dev": true, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "bundled": true, + "dev": true + } + } + } + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "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=", + "dev": true + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object.assign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", + "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true + }, + "onetime": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "p-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", + "dev": true + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true + }, + "pad-right": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz", + "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "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 + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true + }, + "pkg-conf": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.0.0.tgz", + "integrity": "sha1-BxyHZQQDvM+5xif1h1G/5HwGcnk=", + "dev": true, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true + } + } + }, + "pkg-config": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-config/-/pkg-config-1.1.1.tgz", + "integrity": "sha1-VX7yLXPaPIg3EHdmxS6tq94pj+Q=", + "dev": true + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true + }, + "pkg-up": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", + "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", + "dev": true + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "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 + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", + "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", + "dev": true + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true + }, + "readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "dev": true + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true + }, + "redis-commands": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz", + "integrity": "sha1-gdgm9F+pyLIBH0zXoP5ZfSQdRCs=" + }, + "redis-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "dev": true + }, + "require-stack": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/require-stack/-/require-stack-1.0.2.tgz", + "integrity": "sha1-4A7jSL+Wy1w+LUwntJ5BR24Ill0=", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true + }, + "resolve": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.3.3.tgz", + "integrity": "sha1-ZVkHw0aahoDcLeOidaj91paR8OU=", + "dev": true + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true + }, + "retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=", + "dev": true + }, + "right-pad": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/right-pad/-/right-pad-1.0.1.tgz", + "integrity": "sha1-jKCMLLtbVedNr6lr9/0aJ9VoyNA=", + "dev": true + }, + "rimraf": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true + }, + "run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "dev": true + }, + "run-parallel": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.6.tgz", + "integrity": "sha1-KQA8miFj4B4tLfyQV18sbB1hoDk=", + "dev": true + }, + "rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "dev": true + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true + }, + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "standard": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/standard/-/standard-10.0.2.tgz", + "integrity": "sha1-l0wcU8yGWwdaS1dueEQeFpXar3s=", + "dev": true + }, + "standard-engine": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/standard-engine/-/standard-engine-7.0.0.tgz", + "integrity": "sha1-67d7nI/CyBZf+jU72Rug3/Qa9pA=", + "dev": true + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "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": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "syntax-error": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.3.0.tgz", + "integrity": "sha1-HtkmbE1AvnXcVb+bsct3Biu5bKE=", + "dev": true + }, + "table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "dev": true, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "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 + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "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 + } + } + }, + "test-console": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/test-console/-/test-console-1.0.0.tgz", + "integrity": "sha1-EYux4mmIhDo5hYVKCtzktHLDhQE=", + "dev": true + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", + "dev": true + }, + "tryit": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", + "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", + "dev": true + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true + }, + "type-detect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-1.0.0.tgz", + "integrity": "sha1-diIXzAbbJY7EiQihKY6LlRIejqI=", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + }, + "variable-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/variable-diff/-/variable-diff-1.1.0.tgz", + "integrity": "sha1-0r1cZtt2wTh52W5qMG7cmJ35eNo=", + "dev": true + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "dev": true + }, + "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 + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + } + } +} diff --git a/package.json b/package.json index b62f61b..2e7f8b0 100644 --- a/package.json +++ b/package.json @@ -1,45 +1,40 @@ { - "name": "adonis-redis", + "name": "@adonisjs/redis", "version": "1.0.1", "description": "AdonisJs official redis provider to make working with redis fun and simple.", "dependencies": { - "cat-log": "^1.0.2", - "co": "^4.6.0", - "harmony-reflect": "^1.4.2", - "ioredis": "^2.4.2", - "lodash": "^4.13.1", - "node-exceptions": "^2.0.0" + "debug": "^2.6.8", + "ioredis": "^3.1.1", + "lodash": "^4.17.4", + "node-exceptions": "^2.0.2" }, "devDependencies": { - "adonis-fold": "^3.0.2", - "chai": "^3.4.1", - "co-mocha": "^1.1.2", - "coveralls": "^2.11.9", + "@adonisjs/fold": "^4.0.0", + "@adonisjs/sink": "^1.0.9", + "coveralls": "^2.13.1", "cz-conventional-changelog": "^2.0.0", - "istanbul": "^0.4.1", - "mocha": "^3.2.0", - "mocha-lcov-reporter": "^1.2.0", - "shelljs": "^0.7.4", - "standard": "^10.0.0-beta.0", + "japa": "^1.0.3", + "japa-cli": "^1.0.1", + "nyc": "^11.0.3", + "standard": "^10.0.2", "test-console": "^1.0.0" }, "scripts": { - "test": "node ./bin/test", - "lint": "standard src/**/*.js test/*.js providers/*.js", - "coverage": "node ./bin/coverage" + "lint": "standard", + "pretest": "npm run lint", + "posttest": "npm run coverage", + "test:local": "FORCE_COLOR=true node bin/index.js --local", + "test": "nyc npm run test:local", + "test:win": "set FORCE_COLOR=true && node bin/index.js --win", + "coverage": "nyc report --reporter=text-lcov | coveralls" }, "standard": { "globals": [ - "describe", - "it", - "context", - "before", - "after", - "beforeEach", - "afterEach" + "use", + "make" ] }, - "author": "adonisjs", + "author": "virk", "license": "MIT", "config": { "commitizen": { diff --git a/providers/RedisFactoryProvider.js b/providers/RedisFactoryProvider.js index c5b9dfc..cae34c7 100644 --- a/providers/RedisFactoryProvider.js +++ b/providers/RedisFactoryProvider.js @@ -9,16 +9,14 @@ * file that was distributed with this source code. */ -const ServiceProvider = require('adonis-fold').ServiceProvider +const { ServiceProvider } = require('@adonisjs/fold') class RedisFactoryProvider extends ServiceProvider { - - * register () { + register () { this.app.bind('Adonis/Addons/RedisFactory', function () { return require('../src/RedisFactory') }) } - } module.exports = RedisFactoryProvider diff --git a/providers/RedisProvider.js b/providers/RedisProvider.js index 2fbd772..ac9765d 100644 --- a/providers/RedisProvider.js +++ b/providers/RedisProvider.js @@ -9,20 +9,17 @@ * file that was distributed with this source code. */ -const ServiceProvider = require('adonis-fold').ServiceProvider +const { ServiceProvider } = require('@adonisjs/fold') class RedisProvider extends ServiceProvider { - - * register () { + register () { this.app.singleton('Adonis/Addons/Redis', function (app) { const RedisFactory = app.use('Adonis/Addons/RedisFactory') const Config = app.use('Adonis/Src/Config') - const Helpers = app.use('Adonis/Src/Helpers') const Redis = require('../src/Redis') - return new Redis(Config, Helpers, RedisFactory) + return new Redis(Config, RedisFactory) }) } - } module.exports = RedisProvider diff --git a/src/Redis/index.js b/src/Redis/index.js index 12af9e9..d87bee4 100644 --- a/src/Redis/index.js +++ b/src/Redis/index.js @@ -1,101 +1,103 @@ 'use strict' -/** +/* * adonis-redis - * Copyright(c) 2015-2015- Harminder Virk - * MIT Licensed - */ + * + * (c) Harminder Virk + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. +*/ -require('harmony-reflect') const NE = require('node-exceptions') -const CatLog = require('cat-log') const _ = require('lodash') -const logger = new CatLog('adonis:redis') const proxyHandler = require('./proxyHandler') +/** + * Redis class is used to call methods on a redis server. + * This library creates a pool of connections and reuse + * them. + * + * @namespace Adonis/Addons/Redis + * @singleton + * @alias Redis + * + * @class Redis + * @constructor + */ class Redis { - - constructor (Config, Helpers, Factory) { + constructor (Config, Factory) { this.Config = Config - this.Helpers = Helpers this.Factory = Factory this.connectionPools = {} return new Proxy(this, proxyHandler) } /** - * returns configuration for a given connection - * from config/redis.js file. - * - * @param {String} connection + * Looks at the config file and tells if a + * cluster connection to be created or + * not * - * @return {Object} + * @param {Object} config * - * @throws {RuntimeException} If default connection is not found. + * @return {Boolean} * * @private */ - _getConfig (connection) { - if (connection === 'default') { - connection = this.Config.get('redis.connection') - if (!connection) { - throw new NE.RuntimeException('Make sure to define a default connection for redis') - } - } - logger.verbose('getting config for %s connection', connection) - return this.Config.get(`redis.${connection}`) + _isCluster (config) { + return !!config.clusters } /** - * returns redis factory instance for a given connection + * Closes a given redis connection by quitting + * and removing it from the connectionsPool. * * @param {String} connection * - * @return {Object} - * * @private */ - _getConnection (connection) { - if (!this.connectionPools[connection]) { - const config = this._getConfig(connection) - if (!config) { - throw new NE.RuntimeException(`Cannot get redis configuration for ${connection} connection`) - } - this.connectionPools[connection] = new this.Factory(config, this.Helpers, this._isCluster(config)) + _closeConnection (connection) { + const redisConnection = this.connectionPools[connection] + if (!redisConnection) { + return } - return this.connectionPools[connection] + _.unset(this.connectionPools, connection) + return redisConnection.quit() } /** - * tells whether a user intends to use cluster - * - * @param {Object} config + * Returns instance of a new factory instance for + * a given connection. * - * @return {Boolean} + * @param {String} [connection=''] * - * @private + * @return {RedisFactory} */ - _isCluster (config) { - return !!config.clusters - } + connection (connection = '') { + connection = connection || this.Config.get('redis.connection') - /** - * returns instance of a new factory instance for - * a given connection - * - * @param {String} [connection=default] - * - * @return {Object} Instance of redis factory - * - * @public - */ - connection (connection) { - connection = connection || 'default' - return this._getConnection(connection) + /** + * Return the existing connection if exists + */ + if (this.connectionPools[connection]) { + return this.connectionPools[connection] + } + + /** + * Get config + */ + const config = this.Config.get(`redis.${connection}`) + + if (!config || !_.size(config) === 0) { + throw new NE.RuntimeException(`Cannot get redis configuration for ${connection} connection`) + } + + this.connectionPools[connection] = new this.Factory(config, this._isCluster(config)) + return this.connectionPools[connection] } /** - * returns all connections pools + * Returns a hash of connection pools * * @return {Object} * @@ -106,37 +108,16 @@ class Redis { } /** - * closes a single or number of redis connections + * Closes a single or number of redis connections * * @param {Spread} connections * * @public */ - quit () { - const connections = _.size(arguments) ? _.toArray(arguments) : _.keys(this.getConnections()) - return Promise.all(_.map(connections, (connection) => { - return this._closeConnection(connection) - })) + quit (...name) { + const connections = _.isArray(name) ? name : [name] + return Promise.all(_.map(connections, (connection) => this._closeConnection(connection))) } - - /** - * closes a given redis connection by quitting - * and removing it from the connectionsPool. - * - * @param {String} connection - * - * @private - */ - _closeConnection (connection) { - const redisConnection = this.connectionPools[connection] || null - if (!redisConnection) { - logger.warn('trying to close a non-existing redis connection named %s', connection) - return - } - _.unset(this.connectionPools, connection) - return redisConnection.quit() - } - } module.exports = Redis diff --git a/src/Redis/proxyHandler.js b/src/Redis/proxyHandler.js index 9f2b1e2..dfc6a66 100644 --- a/src/Redis/proxyHandler.js +++ b/src/Redis/proxyHandler.js @@ -12,8 +12,19 @@ const proxyHandler = exports = module.exports = {} proxyHandler.get = function (target, name) { - if (target[name]) { + /** + * Node.js inspecting target + */ + if (typeof (name) === 'symbol' || name === 'inspect') { return target[name] } - return target.connection('default')[name] + + /** + * Property exists on target + */ + if (typeof (target[name]) !== 'undefined') { + return target[name] + } + + return target.connection()[name] } diff --git a/src/RedisFactory/index.js b/src/RedisFactory/index.js index 99781f4..9d41d63 100644 --- a/src/RedisFactory/index.js +++ b/src/RedisFactory/index.js @@ -9,63 +9,64 @@ * file that was distributed with this source code. */ -require('harmony-reflect') -const IoRedis = require('ioredis') const _ = require('lodash') -const NE = require('node-exceptions') -const CatLog = require('cat-log') -const logger = new CatLog('adonis:redis') -const RedisSubscriber = require('../Subscribers/Subscriber') -const RedisPSubscriber = require('../Subscribers/PSubscriber') +const IoRedis = require('ioredis') +const debug = require('debug')('adonis:redis') +const { resolver } = require('@adonisjs/fold') + const proxyHandler = require('./proxyHandler') -const Ioc = require('adonis-fold').Ioc class RedisFactory { + constructor (config, useCluster = false) { + this._config = config + this._useCluster = useCluster + + /** + * The main redis connection. + * + * @attribute connection + * + * @type {Object} + */ + this.connection = null - constructor (config, helpers, useCluster) { - this.config = config - this.useCluster = useCluster || false - this.listenersPath = 'Listeners' - this.helpers = helpers + /** + * The list of subscribers for different channels + * + * @type {Array} + */ + this.subscribers = {} + + /** + * The list of psubscribers for different channels + * + * @type {Array} + */ + this.psubscribers = {} - this.redis = this._newConnection() + /** + * The connection for subscribers, this connection is created + * automatically when you register a subscriber. + */ this.subscriberConnection = null - this.subscribers = [] - this.psubscribers = [] - return new Proxy(this, proxyHandler) - } + /** + * Connect to redis + */ + this.connect() - /** - * creates subscriber connection if does not - * exists already - * - * @private - */ - _createSubscriberConnection () { - if (!this.subscriberConnection) { - logger.verbose('creating new subscriber connection') - this.subscriberConnection = this._newConnection() - this._bindListeners() - } + return new Proxy(this, proxyHandler) } /** - * binds redis message listenrs + * Create a new redis connection * - * @private - */ - _bindListeners () { - this.subscriberConnection.on('message', this._notifySubscribers.bind(this)) - this.subscriberConnection.on('pmessage', this._notifyPsubscribers.bind(this)) - } - - /** - * sets up a new redis connection with default configuration + * @method _newConnection * * @return {Object} * - * Example config for cluster + * @example + * ```js * { * clusters: [{ * port: 6380, @@ -73,227 +74,283 @@ class RedisFactory { * }], * redisOptions: {} * } + * ``` * * @private */ _newConnection () { - if (this.useCluster) { - logger.verbose('creating new redis cluster using config: %j', this.config) - return new IoRedis.Cluster(this.config.clusters, {redisOptions: this.config.redisOptions}) + if (this._useCluster) { + debug('creating new redis cluster using config: %j', this._config) + return new IoRedis.Cluster(this._config.clusters, { redisOptions: this._config.redisOptions }) } - logger.verbose('creating new redis connection using config: %j', this.config) - return new IoRedis(this.config) + debug('creating new redis connection using config: %j', this._config) + return new IoRedis(this._config) } /** - * notify all the subscribers when a new message is received - * and they will decided whether to consume the message or - * not + * This method is invoked when redis pub/sub receives + * a new message, it's job is to call the registered + * subscribers * - * @param {String} channel - * @param {Mixed} message + * @method _executeSubscribeListeners * - * @private - */ - _notifySubscribers (channel, message) { - logger.verbose('notifying subscribers for message in %s channel payload: %j', channel, message) - this.subscribers.forEach((subscriber) => subscriber.newMessage(channel, message)) - } - - /** - * notify all the subscribers when a new message is received - * and they will decided whether to consume the message or - * not + * @param {String} channel + * @param {Mixed} message * - * @param {String} pattern - * @param {String} channel - * @param {Mixed} message + * @return {void} * * @private */ - _notifyPsubscribers (pattern, channel, message) { - logger.verbose('notifying psubscribers for new message of %s pattern in %s channel payload: %j', pattern, channel, message) - this.psubscribers.forEach((subscriber) => subscriber.newMessage(pattern, channel, message)) + _executeSubscribeListeners (channel, message) { + if (typeof (this.subscribers[channel]) === 'function') { + this.subscribers[channel](message, channel) + } } /** - * create a redis subscription, it can be using subscribe or psubscribe - * method. + * This method is invoked when redis psubscribe receives + * a new message, it's job is to call the registered + * subscribers + * + * @method _executePSubscribeListeners + * + * @param {String} pattern + * @param {String} channel + * @param {Mixed} message * - * @param {Object} subscriberInstance - * @param {Mixed} subscriptionPayload - * @param {String} type + * @return {void} * * @private */ - _subscribe (subscriberInstance, subscriptionPayload, type) { - this._createSubscriberConnection() - const redisMethod = type === 'subscriber' ? 'subscribe' : 'psubscribe' - const instanceProperty = type === 'subscriber' ? 'subscribers' : 'psubscribers' - this[instanceProperty].push(subscriberInstance) - this.subscriberConnection[redisMethod].apply(this.subscriberConnection, subscriptionPayload) + _executePSubscribeListeners (pattern, channel, message) { + if (typeof (this.psubscribers[pattern]) === 'function') { + this.psubscribers[pattern](pattern, message, channel) + } } /** - * unsubscribe from a given channel/pattern based on the type + * Closes the redis connection first by removing + * all attached listeners + * + * @method _closeConnection * - * @param {Array} channels - * @param {Array} handler - * @param {String} type + * @param {Object} connection + * + * @return {Promise} * * @private */ - _unsubscribe (channels, handler, type) { - let subscriptionPayload = [] - if (typeof (handler) !== 'function') { - channels = channels.concat([handler]) - subscriptionPayload = channels - } else { - subscriptionPayload = channels.concat([handler]) - } - - this._createSubscriberConnection() - const redisMethod = type === 'subscriber' ? 'unsubscribe' : 'punsubscribe' - const instanceProperty = type === 'subscriber' ? 'subscribers' : 'psubscribers' - this.subscriberConnection[redisMethod].apply(this.subscriberConnection, subscriptionPayload) - - /** - * removing the channels from individual subscriber and - * removing it's instance all together when subscriber - * has zero channels. - */ - _.remove(this[instanceProperty], (subscriber) => { - subscriber.unsubscribe(channels) - return !subscriber.hasTopics() + _closeConnection (connection) { + debug('closing redis connection') + return new Promise((resolve, reject) => { + connection.quit((response) => { + connection.removeAllListeners() + return response + }).then(resolve).catch(reject) }) } /** - * validates the handler attached to listen to the subscribed messages. - * Strings will be resolved using the IoC container. + * Creates subscribe connection only if doesn't + * exists + * + * @method _setupSubscriberConnection * - * @param {String|Function} handler - * @throws {InvalidArgumentException} If handler is not resolved as a function + * @return {void} * * @private */ - _validateHandler (handler) { - if (typeof (handler) !== 'function' && (typeof (handler) !== 'object' || !handler.instance || !handler.method)) { - throw new NE.InvalidArgumentException('subscriber needs a handler to listen for new messages') + _setupSubscriberConnection () { + if (!this.subscriberConnection) { + debug('creating new subscription connection') + this.subscriberConnection = this._newConnection() + this.subscriberConnection.on('message', this._executeSubscribeListeners.bind(this)) + this.subscriberConnection.on('pmessage', this._executePSubscribeListeners.bind(this)) } } /** - * resolve handle from the Ioc Container + * Creates a new redis connection * - * @return {Object|Function} + * @method connect * - * @private + * @return {void} */ - _resolveHandler (handler) { - return typeof (handler) === 'string' ? Ioc.makeFunc(this.helpers.makeNameSpace(this.listenersPath, handler)) : handler + connect () { + this.connection = this._newConnection() } /** - * subscribe to number of redis channels. + * Subscribe to a channel * - * @param {...Spread} channels - * @param {Function} handler + * @method subscribe + * @async * - * @return {Object} Subscriber instance + * @param {String} channel + * @param {Function|String} handler * - * @example - * Redis.subscribe('news', 'entertainment', function * (message, channel) { - * }) - * OR - * Redis.subscribe('news', 'entertainment', 'MediaSubscriber.message') - * - * @public + * @return {void} */ - subscribe () { - const channels = _.initial(arguments) - const handler = this._resolveHandler(_.last(arguments)) - this._validateHandler(handler) - const subscriberInstance = new RedisSubscriber(channels, handler) - const subscriptionPayload = channels.concat([subscriberInstance.onSubscribe.bind(subscriberInstance)]) - this._subscribe(subscriberInstance, subscriptionPayload, 'subscriber') - return subscriberInstance + subscribe (channel, handler) { + return new Promise((resolve, reject) => { + if (typeof (handler) !== 'function' && typeof (handler) !== 'string') { + throw new Error('Redis.subscribe needs a callback function or ioc reference string') + } + + const { method } = resolver.forDir('listeners').resolveFunc(handler) + this._setupSubscriberConnection() + + /** + * Cannot have multiple subscribers on a single channel + */ + if (this.subscribers[channel]) { + reject(new Error(`Cannot subscribe to ${channel} channel twice`)) + return + } + + /** + * Otherwise subscribe with redis + */ + debug('setting up subscriber for %s', channel) + this.subscriberConnection.subscribe(channel, (error, count) => { + if (error) { + reject(error) + return + } + this.subscribers[channel] = method + resolve() + }) + }) } /** - * adds a new psubscriber to listen for new messages + * Subscribe to a pattern on redis * - * @return {Object} Psubscriber instance + * @method psubscribe + * @async * - * @example - * Redis.psubscribe('h?llo', function * (message, channel) { - * }) - * OR - * Redis.subscribe('h?llo', 'GreetingSubscriber.message') + * @param {String} pattern + * @param {Function|String} handler * - * @public + * @return {void} */ - psubscribe () { - const patterns = _.initial(arguments) - const handler = this._resolveHandler(_.last(arguments)) - this._validateHandler(handler) - const psubscriberInstance = new RedisPSubscriber(patterns, handler) - const subscriptionPayload = patterns.concat([psubscriberInstance.onSubscribe.bind(psubscriberInstance)]) - this._subscribe(psubscriberInstance, subscriptionPayload, 'psubscriber') - return psubscriberInstance - } + psubscribe (pattern, handler) { + return new Promise((resolve, reject) => { + if (typeof (handler) !== 'function' && typeof (handler) !== 'string') { + throw new Error('Redis.psubscribe needs a callback function or ioc reference string') + } - /** - * unsubscribe from one or multiple redis channels - * - * @param {...Spread} channels - * @param {Function} [handler] - * - * @public - */ - unsubscribe () { - this._unsubscribe(_.initial(arguments), _.last(arguments), 'subscriber') + const { method } = resolver.forDir('listeners').resolveFunc(handler) + this._setupSubscriberConnection() + + /** + * Cannot have multiple subscribers on a single channel + */ + if (this.psubscribers[pattern]) { + reject(new Error(`Cannot subscribe to ${pattern} pattern twice`)) + return + } + + /** + * Otherwise subscribe with redis + */ + debug('setting up psubscriber for %s', pattern) + this.subscriberConnection.psubscribe(pattern, (error, count) => { + if (error) { + reject(error) + return + } + this.psubscribers[pattern] = method + resolve() + }) + }) } /** - * unsubscribe from one or multiple redis channels + * Unsubscribe from a channel. If there are no subscribers for + * any channels, this method will close the subscription + * connection with redis. * - * @param {...Spread} channels - * @param {Function} [handler] + * @method unsubscribe + * @async * - * @public + * @param {String} channel + * + * @return {String} `OK` is return if unsubscribed */ - punsubscribe () { - this._unsubscribe(_.initial(arguments), _.last(arguments), 'psubscriber') + unsubscribe (channel) { + return new Promise((resolve, reject) => { + _.unset(this.subscribers, channel) + + if (!this.subscriberConnection) { + resolve('OK') + } + + this + .subscriberConnection + .unsubscribe(channel) + .then(() => { + /** + * Close subscriber connection when there are no + * subscribers for any channels + */ + if (_.size(this.subscribers) === 0) { + return this._closeConnection(this.subscriberConnection) + } + return 'OK' + }).then(resolve).catch(reject) + }) } /** - * publishes a new message to a given channel + * Unsubscribe from a pattern. If there are no subscribers for + * any patterns, this method will close the subscription + * connection with redis. * - * @param {...Spread} channels - * @param {Mixed} data + * @method punsubscribe + * @async * - * @public + * @param {String} pattern + * + * @return {String} `OK` is return if unsubscribed */ - publish () { - this.redis.publish.apply(this.redis, _.toArray(arguments)) + punsubscribe (pattern) { + return new Promise((resolve, reject) => { + _.unset(this.psubscribers, pattern) + + if (!this.subscriberConnection) { + resolve('OK') + } + + this + .subscriberConnection + .punsubscribe(pattern) + .then(() => { + /** + * Close subscriber connection when there are no + * subscribers for any patterns + */ + if (_.size(this.psubscribers) === 0) { + return this._closeConnection(this.subscriberConnection) + } + return 'OK' + }).then(resolve).catch(reject) + }) } /** - * closes redis and subscriber connection together + * Closes redis connection * * @return {Promise} * * @public */ quit () { - const quitArray = [this.redis.quit()] - if (this.subscriberConnection) { - quitArray.push(this.subscriberConnection.quit()) - } - return Promise.all(quitArray) + return Promise.all(_([this.connection, this.subscriberConnection]) + .filter((connection) => connection && connection.status !== 'end') + .map((connection) => this._closeConnection(connection)) + .value()) } - } module.exports = RedisFactory diff --git a/src/RedisFactory/proxyHandler.js b/src/RedisFactory/proxyHandler.js index 8a79553..5324130 100644 --- a/src/RedisFactory/proxyHandler.js +++ b/src/RedisFactory/proxyHandler.js @@ -21,8 +21,22 @@ let proxyHandler = exports = module.exports = {} * @public */ proxyHandler.get = function (target, name) { - if (target[name]) { + /** + * Node.js inspecting target + */ + if (typeof (name) === 'symbol' || name === 'inspect') { return target[name] } - return target.redis[name] + + /** + * Property exists on target + */ + if (typeof (target[name]) !== 'undefined') { + return target[name] + } + + /** + * Fallback to redis connection + */ + return target.connection[name] } diff --git a/src/Subscribers/BaseSubscriber.js b/src/Subscribers/BaseSubscriber.js index 636a2dc..3f3caac 100644 --- a/src/Subscribers/BaseSubscriber.js +++ b/src/Subscribers/BaseSubscriber.js @@ -9,12 +9,10 @@ * file that was distributed with this source code. */ -const co = require('co') const _ = require('lodash') const util = require('../../lib/util') class BaseSubscriber { - constructor (topics, handler) { this.topics = topics this.handler = handler @@ -77,9 +75,9 @@ class BaseSubscriber { * @private */ _wrapGenerator (instance, method) { - return co.wrap(function * () { - yield method.apply(instance, arguments) - }) + return function () { + method.apply(instance, arguments) + } } /** @@ -175,7 +173,6 @@ class BaseSubscriber { inTopics (topic) { return this.topics.indexOf(topic) > -1 } - } module.exports = BaseSubscriber diff --git a/src/Subscribers/PSubscriber.js b/src/Subscribers/PSubscriber.js index d388b3c..546806c 100644 --- a/src/Subscribers/PSubscriber.js +++ b/src/Subscribers/PSubscriber.js @@ -12,14 +12,12 @@ */ const BaseSubscriber = require('./BaseSubscriber') -const CatLog = require('cat-log') -const logger = new CatLog('adonis:redis') +const debug = require('debug')('adonis:redis') class PSubscriber extends BaseSubscriber { - constructor (patterns, handler) { super(patterns, handler) - logger.verbose('initiating new psubscriber for %j patterns', patterns) + debug('initiating new psubscriber for %j patterns', patterns) } /** @@ -60,9 +58,8 @@ class PSubscriber extends BaseSubscriber { */ unsubscribe (patterns) { super.unsubscribe(patterns) - logger.verbose('unsubscribing from %j patterns', patterns) + debug('unsubscribing from %j patterns', patterns) } - } module.exports = PSubscriber diff --git a/src/Subscribers/Subscriber.js b/src/Subscribers/Subscriber.js index 6b6fba0..c7aa47a 100644 --- a/src/Subscribers/Subscriber.js +++ b/src/Subscribers/Subscriber.js @@ -10,14 +10,12 @@ */ const BaseSubscriber = require('./BaseSubscriber') -const CatLog = require('cat-log') -const logger = new CatLog('adonis:redis') +const debug = require('debug')('adonis:redis') class Subscriber extends BaseSubscriber { - constructor (channels, handler) { super(channels, handler) - logger.verbose('initiating new subscriber for %j channels', channels) + debug('initiating new subscriber for %j channels', channels) } /** @@ -29,9 +27,8 @@ class Subscriber extends BaseSubscriber { */ unsubscribe (channels) { super.unsubscribe(channels) - logger.verbose('unsubscribing from %j channels', channels) + debug('unsubscribing from %j channels', channels) } - } module.exports = Subscriber diff --git a/test/redis-factory.spec.js b/test/redis-factory.spec.js index 4c7474d..638f24a 100644 --- a/test/redis-factory.spec.js +++ b/test/redis-factory.spec.js @@ -8,326 +8,264 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ + +const test = require('japa') +const { ioc } = require('@adonisjs/fold') +const { setupResolver } = require('@adonisjs/sink') + const RedisFactory = require('../src/RedisFactory') -const chai = require('chai') -const Ioc = require('adonis-fold').Ioc -const expect = chai.expect -require('co-mocha') -const Helpers = { - makeNameSpace: function (base, toPath) { - return `App/${base}/${toPath}` - } -} +test.group('RedisFactory', function (group) { + group.before(() => { + ioc.restore() + setupResolver() + }) -describe('RedisFactory', function () { - it('should setup connection with redis', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) + test('should setup connection with redis', (assert, done) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) redis.once('connect', function () { redis.quit().then((response) => { - expect(response).deep.equal(['OK']) + assert.deepEqual(response, ['OK']) done() }).catch(done) }) }) - it('should use proxy to call command over redis client', function * () { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) + test('should use proxy to call command over redis client', async (assert) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) redis.set('foo', 'bar') - const foo = yield redis.get('foo') - expect(foo).to.equal('bar') - yield redis.quit() + const foo = await redis.get('foo') + assert.equal(foo, 'bar') + await redis.quit() }) - it('should proxy ioredis error event', function (done) { + test('should proxy ioredis error event', (assert, done) => { const redis = new RedisFactory({port: 6389, host: 'localhost', retryStrategy: function () { return null }}) redis.on('error', function (error) { - expect(error.code).to.equal('ECONNREFUSED') + assert.equal(error.code, 'ECONNREFUSED') done() }) }) - it('should be able to quit redis connection', function * () { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - const response = yield redis.quit() - expect(response).deep.equal(['OK']) + test('should be able to quit redis connection', async (assert) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + const response = await redis.quit() + assert.deepEqual(response, ['OK']) }) - it('should be able to set/get buffer', function * () { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.set('foo', new Buffer('bar')) - const foo = yield redis.getBuffer('foo') - expect(foo instanceof Buffer).to.equal(true) - yield redis.quit() + test('should be able to set/get buffer', async (assert) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + redis.set('foo', Buffer.from('bar')) + const foo = await redis.getBuffer('foo') + assert.equal(foo instanceof Buffer, true) + await redis.quit() }) - it('should be able to pub/sub', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.subscribe('new:user', function * (message) { - expect(message).to.equal('virk') - yield redis.quit() - done() - }).done(function () { - redis.publish('new:user', 'virk') - }) + test('subscribe to a channel', async (assert) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + await redis.subscribe('news', function () { }) + assert.isDefined(redis.subscribers.news) + await redis.quit() }) - it('should be able to attach normal functions', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.subscribe('new:user', function (message) { - expect(message).to.equal('virk') - redis.quit().then(() => done()).catch(done) - }).done(function () { - redis.publish('new:user', 'virk') - }) + test('subscribing multiple times should throw exception', async (assert) => { + assert.plan(1) + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + await redis.subscribe('news', function () { }) + try { + await redis.subscribe('news', function () { }) + } catch ({ message }) { + assert.equal(message, 'Cannot subscribe to news channel twice') + } + await redis.quit() }) - it('should be able to define subscriber as an autoload namespace', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - const RedisSubscriber = { - * onNewUser (message) { - expect(message).to.equal('virk') - yield redis.quit() - done() - } + test('do not register any subscribers when unable to subscribe', async (assert) => { + assert.plan(3) + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + redis.subscriberConnection = redis._newConnection() + try { + await redis.subscriberConnection.quit() + await redis.subscribe('news', function () { }) + } catch ({ message }) { + assert.equal(message, 'Connection is closed.') + assert.deepEqual(redis.subscribers, {}) + assert.equal(redis.subscriberConnection.listenerCount('message'), 0) } - Ioc.bind('App/Listeners/Redis', function () { - return RedisSubscriber - }) - redis.subscribe('new:user', 'Redis.onNewUser').done(function () { - redis.publish('new:user', 'virk') - }) + await redis.quit() }) - it('ioc referenced listener should maintain the scope', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) + test('should be able to define subscriber as an autoload namespace', (assert, done) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) const RedisSubscriber = { - name: 'foo', - * onNewUser (message) { - expect(message).to.equal('virk') - expect(this.name).to.equal('foo') - yield redis.quit() + async onNewUser (message) { + assert.equal(message, 'virk') + await redis.quit() done() } } - Ioc.bind('App/Listeners/Redis', function () { + + ioc.fake('App/Listeners/Redis', function () { return RedisSubscriber }) - redis.subscribe('new:user', 'Redis.onNewUser').done(function () { - redis.publish('new:user', 'virk') - }) - }) - it('should throw error when subscriber handler is not defined', function () { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - const fn = function () { - return redis.subscribe('bar', {}) - } - expect(fn).to.throw(/subscriber needs a handler to listen for new messages/) + redis + .subscribe('new:user', 'Redis.onNewUser') + .then(() => { + redis.publish('new:user', 'virk') + }).catch(done) }) - it('should not listen to messages on different channels', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.subscribe('bar', function * (message, channel) { - expect(channel).to.equal('bar') - redis.unsubscribe('bar', function () {}) - yield redis.quit() + test('unsubscribe from a channel', (assert, done) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + redis + .subscribe('new:user', function () {}) + .then(() => { + return redis.unsubscribe('new:user') + }).then(() => { + assert.isUndefined(redis.subscribers['new:user']) + assert.deepEqual(redis.subscribers, {}) + assert.equal(redis.subscriberConnection.listenerCount('message'), 0) + assert.equal(redis.subscriberConnection.listenerCount('pmessage'), 0) + return redis.quit() + }).then(() => { done() - }).done(function () { - redis.publish('foo', 'baz') - redis.publish('bar', 'baz') - }) + }).catch(done) }) - it('should be able to subscribe to multiple channels', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - let x = 0 - redis.subscribe('foo', 'bar', function * (message, channel) { - x++ - expect(channel).to.be.oneOf(['foo', 'bar']) - if (x === 2) { - redis.unsubscribe('foo', 'bar', function () {}) - yield redis.quit() - done() - } - }).done(function () { - redis.publish('foo', 'baz') - redis.publish('bar', 'baz') - }) - }) - - it('should be able to pipe commands', function * () { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - const pipe = redis.pipeline() - const currentTime = new Date().getTime() - pipe.set('time', currentTime) - pipe.get('time') - const result = yield pipe.exec() - expect(result[1][1]).to.equal(currentTime.toString()) - yield redis.quit() - }) - - it('should remove subscriber for a given channel when unsubscribe method is called', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.subscribe('bar', 'foo', function * (message, channel) { - expect(channel).to.equal('bar') - redis.unsubscribe('bar', function () {}) - expect(redis.subscribers.length).to.equal(1) - yield redis.quit() - done() - }).done(function () { - redis.publish('bar', 'Hello') - }) + test('subscribe to a pattern', async (assert) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + await redis.psubscribe('new?', function () { }) + assert.isDefined(redis.psubscribers['new?']) + await redis.quit() }) - it('should remove multiple subscribers for a given channel when unsubscribe method is called', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.subscribe('bar', 'foo', function * (message, channel) { - expect(channel).to.equal('bar') - redis.unsubscribe('bar', 'foo') - expect(redis.subscribers.length).to.equal(0) - yield redis.quit() - done() - }).done(function () { - redis.publish('bar', 'Hello') - }) + test('receive messages related to a pattern', (assert, done) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + redis + .psubscribe('new?', async function (pattern, message, channel) { + assert.equal(pattern, 'new?') + assert.equal(message, 'hello') + assert.equal(channel, 'news') + await redis.quit() + done() + }) + .then(() => { + redis.publish('news', 'hello') + }) }) - it('should remove subscribers using unsubscribe when last argument is not a callback', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.subscribe('bar', function * (message, channel) { - try { - expect(channel).to.equal('bar') - redis.unsubscribe('bar') - expect(redis.subscribers.length).to.equal(0) - yield redis.quit() + test('unsubscribe from a pattern', (assert, done) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + redis + .psubscribe('new?', function () {}) + .then(() => { + return redis.punsubscribe('new?') + }) + .then(() => { + assert.isUndefined(redis.psubscribers['new:user']) + assert.deepEqual(redis.psubscribers, {}) + assert.equal(redis.subscriberConnection.listenerCount('message'), 0) + assert.equal(redis.subscriberConnection.listenerCount('pmessage'), 0) + return redis.quit() + }).then(() => { done() - } catch (e) { - done(e) - } - }).done(function () { - redis.publish('bar', 'Hello') - }) + }).catch(done) }) - it('should be able to psubscribe to a pattern', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.psubscribe('h?llo', function * (message, channel, pattern) { - expect(message).to.equal('virk') - expect(channel).to.equal('hello') - expect(pattern).to.equal('h?llo') - redis.punsubscribe('h?llo') - yield redis.quit() - done() - }).done(function () { - redis.publish('hello', 'virk') - }) - }) + test('should throw error when subscriber handler is not defined', async (assert) => { + assert.plan(1) + const redis = new RedisFactory({port: 6379, host: 'localhost'}) - it('should be able to psubscribe and attach an autoload path as a listener', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - const RedisSubscriber = { - * onGreeting (message, channel, pattern) { - expect(message).to.equal('virk') - expect(channel).to.equal('hello') - expect(pattern).to.equal('h?llo') - redis.punsubscribe('h?llo') - yield redis.quit() - done() - } + try { + await redis.subscribe('bar', {}) + } catch ({ message }) { + assert.equal(message, 'Redis.subscribe needs a callback function or ioc reference string') } - Ioc.bind('App/Listeners/Redis', function () { - return RedisSubscriber - }) - redis.psubscribe('h?llo', 'Redis.onGreeting').done(function () { - redis.publish('hello', 'virk') - }) }) - it('should be able to psubscribe plain functions', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - const RedisSubscriber = { - onGreeting (message, channel, pattern) { - expect(message).to.equal('virk') - expect(channel).to.equal('hello') - expect(pattern).to.equal('h?llo') - redis.punsubscribe('h?llo') - redis.quit().then(() => done()).catch(done) - } + test('should throw error when pattern subscriber handler is not defined', async (assert) => { + assert.plan(1) + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + + try { + await redis.psubscribe('new?', {}) + } catch ({ message }) { + assert.equal(message, 'Redis.psubscribe needs a callback function or ioc reference string') } - Ioc.bind('App/Listeners/Redis', function () { - return RedisSubscriber - }) - redis.psubscribe('h?llo', 'Redis.onGreeting').done(function () { - redis.publish('hello', 'virk') - }) }) - it('should be able to unsubscribe from a pattern subscription', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.psubscribe('h?llo', function * (message, channel, pattern) { - redis.punsubscribe('h?llo') - expect(redis.psubscribers.length).to.equal(0) - yield redis.quit() + test('should not listen to messages on different channels', (assert, done) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + redis.subscribe('bar', async (message, channel) => { + assert.equal(channel, 'bar') + await redis.quit() done() - }).done(function () { - redis.publish('hello', 'virk') + }).then(function () { + redis.publish('foo', 'baz') + redis.publish('bar', 'baz') }) }) - it('should be able to pattern subscribe to multiple patterns', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - let messagesCount = 0 - redis.psubscribe('h?llo', 'f?eak', function * (message, channel, pattern) { - messagesCount++ - expect(pattern).to.be.oneOf(['h?llo', 'f?eak']) - expect(message).to.equal('virk') - if (messagesCount === 2) { - redis.punsubscribe('h?llo') - redis.punsubscribe('f?eak') - yield redis.quit() - done() - } - }).done(function () { - redis.publish('hello', 'virk') - redis.publish('freak', 'virk') - }) + // test('should be able to subscribe to multiple channels', (assert, done) => { + // const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) + // let x = 0 + // redis.subscribe('foo', 'bar', async (message, channel) => { + // x++ + // expect(channel).to.be.oneOf(['foo', 'bar']) + // if (x === 2) { + // redis.unsubscribe('foo', 'bar', function () {}) + // await redis.quit() + // done() + // } + // }).done(function () { + // redis.publish('foo', 'baz') + // redis.publish('bar', 'baz') + // }) + // }) + + test('should be able to pipe commands', async (assert) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + const pipe = redis.pipeline() + const currentTime = new Date().getTime() + pipe.set('time', currentTime) + pipe.get('time') + const result = await pipe.exec() + assert.equal(result[1][1], currentTime.toString()) + await redis.quit() }) - it('should return 0 as count when trying to unsubscribe from unknown channels', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.unsubscribe('bar', function (err, counts) { - expect(err).not.to.exist - expect(counts).to.equal(0) - done() - }) + test('should not throw exception when unsubscribing from unknown channels', async (assert) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + await redis.unsubscribe('bar') + await redis.quit() }) - it('should return 0 as count when trying to punsubscribe from unknown channels', function (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.punsubscribe('bar', function (err, counts) { - expect(err).not.to.exist - expect(counts).to.equal(0) - done() - }) + test('should not throw exception when unsubscribing from unknown channels', async (assert) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + await redis.punsubscribe('new?') + await redis.quit() }) - it('should be able to pipeline commands', function * () { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - const results = yield redis.pipeline().set('foo', 'bar').get('foo').exec() - expect(results).deep.equal([[null, 'OK'], [null, 'bar']]) - yield redis.quit() + test('should be able to pipeline commands', async (assert) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + const results = await redis.pipeline().set('foo', 'bar').get('foo').exec() + assert.deepEqual(results, [[null, 'OK'], [null, 'bar']]) + await redis.quit() }) - it('should close subscriber connection with normal connection when quit is called', function * (done) { - const redis = new RedisFactory({port: 6379, host: 'localhost'}, Helpers) - redis.subscribe('foo', function * () {}) - const response = yield redis.quit() - expect(response).deep.equal(['OK', 'OK']) - setTimeout(function () { - expect(redis.redis.status).to.equal('end') - expect(redis.subscriberConnection.status).to.equal('end') - done() - }) + test('should close subscriber connection with normal connection when quit is called', (assert, done) => { + const redis = new RedisFactory({port: 6379, host: 'localhost'}) + redis.subscribe('foo', async function () {}) + redis + .quit() + .then((response) => { + assert.deepEqual(response, ['OK', 'OK']) + setTimeout(() => { + assert.equal(redis.connection.status, 'end') + assert.equal(redis.subscriberConnection.status, 'end') + done() + }) + }).catch(done) }) }) diff --git a/test/redis.spec.js b/test/redis.spec.js index 724398f..c487c47 100644 --- a/test/redis.spec.js +++ b/test/redis.spec.js @@ -9,112 +9,149 @@ * file that was distributed with this source code. */ +const test = require('japa') +const { Config } = require('@adonisjs/sink') const Redis = require('../src/Redis') const RedisFactory = require('../src/RedisFactory') -const chai = require('chai') -const expect = chai.expect -const stderr = require('test-console').stderr - -require('co-mocha') - -const Config = { - get: function (key) { - switch (key) { - case 'redis.connection': - return 'primary' - case 'redis.primary': - return {port: 6379, host: 'localhost'} - case 'redis.secondary': - return {port: 6379, host: 'localhost'} - } - } -} - -describe('Redis', function () { - it('should throw exception when connection is not defined in redis config file', function () { - const connection = new Redis({get: function () {}}, {}, RedisFactory) - const fn = () => connection._getConfig('default') - expect(fn).to.throw(/Make sure to define a default connection for redis/) + +test.group('Redis', () => { + test('should throw exception when connection is not defined in redis config file', (assert) => { + const connection = new Redis(new Config(), RedisFactory) + const fn = () => connection._getConfig() + assert.throw(fn, /Cannot get redis configuration for undefined connection/) }) - it('should return the instance of redis factory when using _getConnection method', function () { - const connection = new Redis(Config, {}, RedisFactory) - expect(connection._getConnection('default') instanceof RedisFactory).to.equal(true) + test('should return the instance of redis factory when using _getConnection method', (assert) => { + const config = new Config() + config.set('redis', { + connection: 'primary', + primary: { host: '127.0.0.1', port: 6379 } + }) + const connection = new Redis(config, RedisFactory) + assert.equal(connection.connection() instanceof RedisFactory, true) }) - it('should return the instance of redis factory when using connection method', function () { - const redis = new Redis(Config, {}, RedisFactory) - expect(redis.connection() instanceof RedisFactory).to.equal(true) + test('should return the instance of redis factory when using connection method', (assert) => { + const config = new Config() + config.set('redis', { + connection: 'primary', + primary: { host: '127.0.0.1', port: 6379 } + }) + + const redis = new Redis(config, RedisFactory) + assert.equal(redis.connection() instanceof RedisFactory, true) }) - it('should throw error when unable to find config for a given connection', function () { - const connection = new Redis(Config, {}, RedisFactory) - const fn = () => connection._getConnection('foo') - expect(fn).to.throw(/Cannot get redis configuration for foo connection/) + test('should throw error when unable to find config for a given connection', (assert) => { + const config = new Config() + config.set('redis', { + connection: 'primary', + primary: { host: '127.0.0.1', port: 6379 } + }) + + const connection = new Redis(config, RedisFactory) + const fn = () => connection.connection('foo') + assert.throw(fn, /Cannot get redis configuration for foo connection/) }) - it('should proxy redis factory methods', function () { - const redis = new Redis(Config, {}, RedisFactory) + test('should proxy redis factory methods', (assert) => { + const config = new Config() + config.set('redis', { + connection: 'primary', + primary: { host: '127.0.0.1', port: 6379 } + }) + + const redis = new Redis(config, RedisFactory) const get = redis.get - expect(get).to.be.a('function') + assert.isFunction(get, 'function') }) - it('should be able to connect to redis to set and get data', function * () { - const redis = new Redis(Config, {}, RedisFactory) + test('should be able to connect to redis to set and get data', async (assert) => { + const config = new Config() + config.set('redis', { + connection: 'primary', + primary: { host: '127.0.0.1', port: 6379 } + }) + + const redis = new Redis(config, RedisFactory) redis.set('foo', 'bar') - const foo = yield redis.get('foo') - expect(foo).to.equal('bar') + const foo = await redis.get('foo') + assert.equal(foo, 'bar') redis.quit() }) - it('should reuse the connection pool when trying to access redis for same connection', function * () { - const redis = new Redis(Config, {}, RedisFactory) + test('should reuse the connection pool when trying to access redis for same connection', async (assert) => { + const config = new Config() + config.set('redis', { + connection: 'primary', + primary: { host: '127.0.0.1', port: 6379 } + }) + + const redis = new Redis(config, RedisFactory) redis.set('foo', 'bar') - yield redis.get('foo') - expect(Object.keys(redis.getConnections()).length).to.equal(1) - expect(redis.getConnections()).to.have.property('default') + await redis.get('foo') + assert.equal(Object.keys(redis.getConnections()).length, 1) + assert.property(redis.getConnections(), 'primary') redis.quit() }) - it('should reuse the connection pool when trying to access redis for same connection', function * () { - const redis = new Redis(Config, {}, RedisFactory) + test('should reuse the connection pool when trying to access redis for same connection', async (assert) => { + const config = new Config() + config.set('redis', { + connection: 'primary', + primary: { host: '127.0.0.1', port: 6379 } + }) + + const redis = new Redis(config, RedisFactory) redis.set('foo', 'bar') - yield redis.get('foo') - expect(Object.keys(redis.getConnections()).length).to.equal(1) - expect(redis.getConnections()).to.have.property('default') + await redis.get('foo') + assert.equal(Object.keys(redis.getConnections()).length, 1) + assert.property(redis.getConnections(), 'primary') redis.quit() }) - it('should close a given connection using quit method', function * () { - const redis = new Redis(Config, {}, RedisFactory) + test('should close a given connection using quit method', async (assert) => { + const config = new Config() + config.set('redis', { + connection: 'primary', + primary: { host: '127.0.0.1', port: 6379 } + }) + + const redis = new Redis(config, RedisFactory) redis.set('foo', 'bar') - const response = yield redis.quit('default') - expect(response).deep.equal([['OK']]) - expect(Object.keys(redis.getConnections()).length).to.equal(0) + const response = await redis.quit('primary') + assert.deepEqual(response, [['OK']]) + assert.equal(Object.keys(redis.getConnections()).length, 0) }) - it('should throw an error event when unable to connect to redis', function (done) { - const redis = new Redis({get: function () { return {port: 6389, host: 'localhost'} }}, {}, RedisFactory) + test('should throw an error event when unable to connect to redis', function (assert, done) { + const config = new Config() + config.set('redis', { + connection: 'primary', + primary: { host: '127.0.0.1', port: 6389 }, + secondary: 'self::redis.primary' + }) + + const redis = new Redis(config, RedisFactory) redis.on('error', (error) => { - expect(error.code).to.equal('ECONNREFUSED') + assert.equal(error.code, 'ECONNREFUSED') done() }) }) - it('should be able to create a new redis connection using connection method', function * () { - const redis = new Redis(Config, {}, RedisFactory) - redis.connection('secondary').set('foo', 'bar') - const foo = yield redis.connection('secondary').get('foo') - expect(foo).to.equal('bar') - expect(Object.keys(redis.getConnections()).length).to.equal(1) - expect(redis.getConnections()).to.have.property('secondary') - }) + test('should be able to create a new redis connection using connection method', async (assert) => { + const config = new Config() + config.set('redis', { + connection: 'primary', + primary: { host: '127.0.0.1', port: 6379 }, + secondary: 'self::redis.primary' + }) - it('should warn when trying to close a non-existing connection', function () { - const redis = new Redis(Config, {}, RedisFactory) - const inspect = stderr.inspect() - redis.quit('default') - inspect.restore() - expect(inspect.output[inspect.output.length - 1]).to.match(/trying to close a non-existing redis connection named default/) + const redis = new Redis(config, RedisFactory) + redis.connection('secondary').set('foo', 'bar') + const foo = await redis.connection('secondary').get('foo') + assert.equal(foo, 'bar') + assert.equal(Object.keys(redis.getConnections()).length, 1) + assert.property(redis.getConnections(), 'secondary') }) })