├── .gitignore ├── async-resolver-logo.png ├── .travis.yml ├── index.js ├── LICENSE ├── package.json ├── README.md ├── test └── index.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .nyc_output 3 | .idea 4 | .DS_Store 5 | thumbs.db 6 | *.log* 7 | coverage -------------------------------------------------------------------------------- /async-resolver-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ApoorvSaxena/async-resolver/HEAD/async-resolver-logo.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '8' 5 | script: 6 | - npm run test 7 | after_success: 'npm run coveralls' -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const Promise = require('bluebird'); 2 | 3 | let Resolver = function() { 4 | let channels = {}; 5 | 6 | function getSubscribers(channel) { 7 | channels[channel] = channels[channel] || []; 8 | return channels[channel]; 9 | } 10 | 11 | function setSubscriber(channel, callback) { 12 | getSubscribers(channel); 13 | channels[channel].push(callback); 14 | } 15 | 16 | return { 17 | publish: function(channel, config, data) { 18 | config = config || { 19 | promiseMethod: 'all' 20 | }; 21 | let promises = [], 22 | channels = getSubscribers(channel); 23 | 24 | if(channels.length > 0) { 25 | for (var i = 0; i < channels.length; i++) { 26 | promises.push(channels[i](data)); 27 | } 28 | return Promise[config.promiseMethod](promises); 29 | } 30 | return Promise.resolve(); 31 | }, 32 | subscribe: function(channel, callback) { 33 | setSubscriber(channel, callback); 34 | } 35 | } 36 | } 37 | 38 | module.exports = Resolver; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Apoorv Saxena 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "async-resolver", 3 | "version": "0.0.2", 4 | "description": "Asynchronously resolve subscribed decisions in pub-sub architecture", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "./node_modules/istanbul/lib/cli.js cover ./node_modules/.bin/_mocha", 11 | "coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls" 12 | }, 13 | "keywords": [ 14 | "async", 15 | "promise", 16 | "decision", 17 | "resolve", 18 | "function", 19 | "pubsub" 20 | ], 21 | "author": { 22 | "name": "Apoorv Saxena", 23 | "email": "root@apoorv.pro", 24 | "url": "https://apoorv.pro" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "git://github.com/ApoorvSaxena/async-resolver.git" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/ApoorvSaxena/async-resolver/issues" 32 | }, 33 | "licenses": [ 34 | { 35 | "type": "MIT", 36 | "url": "https://github.com/ApoorvSaxena/async-resolver/blob/master/LICENSE" 37 | } 38 | ], 39 | "files": [ 40 | "index.js" 41 | ], 42 | "license": "MIT", 43 | "dependencies": { 44 | "bluebird": "^3.5.1" 45 | }, 46 | "devDependencies": { 47 | "coveralls": "^3.0.1", 48 | "istanbul": "^0.4.5", 49 | "mocha": "^5.2.0" 50 | } 51 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # async-resolver [![Build Status](https://travis-ci.org/ApoorvSaxena/async-resolver.svg?branch=master)](https://travis-ci.org/ApoorvSaxena/async-resolver) [![Coverage Status](https://coveralls.io/repos/github/ApoorvSaxena/async-resolver/badge.svg?branch=master)](https://coveralls.io/github/ApoorvSaxena/async-resolver?branch=master) [![dependencies Status](https://david-dm.org/ApoorvSaxena/async-resolver/status.svg)](https://david-dm.org/ApoorvSaxena/async-resolver) 2 | 3 |

4 | 5 |

6 | 7 | AsyncResolver.js implements a PubSub architecture where subscribers of events are decision makers (return promise when they receive an event) and after publishing an event, publisher gets the decision of the subscribers. Supports both Node and browser. 8 | 9 | ### Where to use? 10 | 11 | There are situations where we want to maintain distinct subscribers of an event, though want to act on the basis of how subscribers react. AsyncResolver.js is the solution for this need, it's an amalgamation of pub sub architecture and promises to provide decision making capability in asynchronous environment. 12 | > For example: Let's consider a case where there are several components on a webpage, whose state can be changed by the user and we make every component to subscribe as listener to listen to a page transition so that we can check if a user is trying to move without saving data. 13 | 14 | > Now, when an individual clicks on a link, we publish an event mentioning of the transition of the user from the page, though we want to ask every listener (or component) if user has made any changes to their state and is moving without saving them. In case there are any unsaved changes in any of the component, then we cancel the transition and instead dispay an information dialog to the user asking him to save information before proceeding further. 15 | 16 | ## Install 17 | 18 | ```sh 19 | ### NPM 20 | npm install async-resolver 21 | 22 | ### Yarn 23 | yarn add async-resolver 24 | ``` 25 | 26 | 27 | ## Usage 28 | 29 | ```js 30 | const AsyncResolver = require('async-resolver'); 31 | let resolver = new AsyncResolver(); 32 | 33 | resolver.subscribe('locationChange', () => { 34 | // custom logic 35 | return Promise.resolve(); 36 | }); 37 | 38 | resolver.subscribe('locationChange', () => { 39 | // custom logic 40 | return Promise.reject(); 41 | }); 42 | 43 | resolver 44 | .publish('locationChange', { 45 | promiseMethod: 'any' 46 | }) 47 | .then(() => console.log('location change allowed')) 48 | .catch(() => console.log('location change denied')) 49 | ``` 50 | 51 | ## API 52 | 53 | ### AsyncResolver() 54 | 55 | Returns `AsyncResolver` function that can be instantiated. 56 | 57 | ### subscribe(eventName, callback) 58 | 59 | Allows subscribing to the event and executing the callback when an event is published. 60 | 61 | #### eventName 62 | 63 | Type: `string` 64 | 65 | Event published. 66 | 67 | #### callback 68 | 69 | Type: `function` 70 | 71 | Callback to be executed when the publish event is received. 72 | 73 | ### publish(eventName, options) 74 | 75 | Returns a promise, that defines the decision of subscribers. 76 | 77 | #### eventName 78 | 79 | Type: `string` 80 | 81 | Event published. 82 | 83 | #### options 84 | 85 | Type: `object` 86 | 87 | Options to be passed while publishing to an event. 88 | 89 | ##### options.promiseMethod 90 | 91 | Type: `string` 92 | 93 | Method to be applied at the collection of promises such as `all`, `any` etc. Here's [list of methods](http://bluebirdjs.com/docs/api/collections.html) supported by Promise collection. 94 | 95 | ## License 96 | 97 | MIT © [Apoorv Saxena](https://apoorv.pro/) -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | const AsyncResolver = require('../index.js'); 2 | const assert = require('assert') 3 | 4 | describe('AsyncResolver', () => { 5 | describe('itself', () => { 6 | it('should be a function', () => { 7 | assert.equal('function', typeof AsyncResolver) 8 | }) 9 | }) 10 | 11 | describe('instance of AsyncResolver', () => { 12 | it('should be an object', () => { 13 | const resolver = new AsyncResolver(); 14 | assert.equal('object', typeof resolver) 15 | }) 16 | 17 | it('should define publish and subscribe functions', () => { 18 | const resolver = new AsyncResolver(); 19 | assert.equal('function', typeof resolver.publish) 20 | assert.equal('function', typeof resolver.subscribe) 21 | }) 22 | }) 23 | 24 | describe('publish function', () => { 25 | it('should resolve when no subscriber is attached', (done) => { 26 | const resolver = new AsyncResolver(); 27 | resolver 28 | .publish('locationChange') 29 | .then(() => { 30 | assert.equal(true, true); 31 | done(); 32 | }) 33 | .catch(() => { 34 | assert.equal(false, true); 35 | done(); 36 | }); 37 | }) 38 | 39 | describe('with ANY as promiseMethod', () => { 40 | it('should resolve when no subscribers attached', (done) => { 41 | const resolver = new AsyncResolver(); 42 | resolver 43 | .publish('locationChange', { 44 | promiseMethod: 'any' 45 | }) 46 | .then(() => { 47 | assert.equal(true, true); 48 | done(); 49 | }) 50 | .catch(() => { 51 | assert.equal(false, true); 52 | done(); 53 | }); 54 | }) 55 | 56 | it('should resolve and when one of the subscribers resolves', (done) => { 57 | const resolver = new AsyncResolver(); 58 | resolver.subscribe('locationChange', () => Promise.resolve()); 59 | resolver.subscribe('locationChange', () => Promise.reject()); 60 | resolver 61 | .publish('locationChange', { 62 | promiseMethod: 'any' 63 | }) 64 | .then(() => { 65 | assert.equal(true, true); 66 | done(); 67 | }) 68 | .catch(() => { 69 | assert.equal(false, true); 70 | done(); 71 | }); 72 | }) 73 | 74 | it('should reject and when none of the subscribers resolves', (done) => { 75 | const resolver = new AsyncResolver(); 76 | resolver.subscribe('locationChange', () => Promise.reject()); 77 | resolver.subscribe('locationChange', () => Promise.reject()); 78 | resolver 79 | .publish('locationChange', { 80 | promiseMethod: 'any' 81 | }) 82 | .then(() => { 83 | assert.equal(false, true); 84 | done(); 85 | }) 86 | .catch(() => { 87 | assert.equal(true, true); 88 | done(); 89 | }); 90 | }) 91 | }) 92 | 93 | describe('with ALL as promiseMethod', () => { 94 | it('should resolve and when no subscribers attached', (done) => { 95 | const resolver = new AsyncResolver(); 96 | resolver 97 | .publish('locationChange', { 98 | promiseMethod: 'all' 99 | }) 100 | .then(() => { 101 | assert.equal(true, true); 102 | done(); 103 | }) 104 | .catch(() => { 105 | assert.equal(false, true); 106 | done(); 107 | }); 108 | }) 109 | 110 | it('should resolve and when all of the subscribers resolves', (done) => { 111 | const resolver = new AsyncResolver(); 112 | resolver.subscribe('locationChange', () => Promise.resolve()); 113 | resolver.subscribe('locationChange', () => Promise.resolve()); 114 | resolver 115 | .publish('locationChange', { 116 | promiseMethod: 'all' 117 | }) 118 | .then(() => { 119 | assert.equal(true, true); 120 | done(); 121 | }) 122 | .catch(() => { 123 | assert.equal(false, true); 124 | done(); 125 | }); 126 | }) 127 | 128 | it('should reject and when one of the subscribers rejects', (done) => { 129 | const resolver = new AsyncResolver(); 130 | resolver.subscribe('locationChange', () => Promise.resolve()); 131 | resolver.subscribe('locationChange', () => Promise.reject()); 132 | resolver 133 | .publish('locationChange', { 134 | promiseMethod: 'all' 135 | }) 136 | .then(() => { 137 | assert.equal(false, true); 138 | done(); 139 | }) 140 | .catch(() => { 141 | assert.equal(true, true); 142 | done(); 143 | }); 144 | }) 145 | }) 146 | }) 147 | }) -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | abbrev@1: 6 | version "1.1.1" 7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 8 | 9 | abbrev@1.0.x: 10 | version "1.0.9" 11 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" 12 | 13 | ajv@^5.1.0: 14 | version "5.5.2" 15 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" 16 | dependencies: 17 | co "^4.6.0" 18 | fast-deep-equal "^1.0.0" 19 | fast-json-stable-stringify "^2.0.0" 20 | json-schema-traverse "^0.3.0" 21 | 22 | amdefine@>=0.0.4: 23 | version "1.0.1" 24 | resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" 25 | 26 | argparse@^1.0.7: 27 | version "1.0.10" 28 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 29 | dependencies: 30 | sprintf-js "~1.0.2" 31 | 32 | asn1@~0.2.3: 33 | version "0.2.3" 34 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" 35 | 36 | assert-plus@1.0.0, assert-plus@^1.0.0: 37 | version "1.0.0" 38 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 39 | 40 | async@1.x: 41 | version "1.5.2" 42 | resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" 43 | 44 | asynckit@^0.4.0: 45 | version "0.4.0" 46 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 47 | 48 | aws-sign2@~0.7.0: 49 | version "0.7.0" 50 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" 51 | 52 | aws4@^1.6.0: 53 | version "1.7.0" 54 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289" 55 | 56 | balanced-match@^1.0.0: 57 | version "1.0.0" 58 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 59 | 60 | bcrypt-pbkdf@^1.0.0: 61 | version "1.0.1" 62 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" 63 | dependencies: 64 | tweetnacl "^0.14.3" 65 | 66 | bluebird@^3.5.1: 67 | version "3.5.1" 68 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" 69 | 70 | brace-expansion@^1.1.7: 71 | version "1.1.11" 72 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 73 | dependencies: 74 | balanced-match "^1.0.0" 75 | concat-map "0.0.1" 76 | 77 | browser-stdout@1.3.1: 78 | version "1.3.1" 79 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 80 | 81 | caseless@~0.12.0: 82 | version "0.12.0" 83 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 84 | 85 | co@^4.6.0: 86 | version "4.6.0" 87 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 88 | 89 | combined-stream@1.0.6, combined-stream@~1.0.5: 90 | version "1.0.6" 91 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818" 92 | dependencies: 93 | delayed-stream "~1.0.0" 94 | 95 | commander@2.15.1: 96 | version "2.15.1" 97 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.15.1.tgz#df46e867d0fc2aec66a34662b406a9ccafff5b0f" 98 | 99 | commander@2.20.0: 100 | version "2.20.0" 101 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" 102 | 103 | concat-map@0.0.1: 104 | version "0.0.1" 105 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 106 | 107 | core-util-is@1.0.2: 108 | version "1.0.2" 109 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 110 | 111 | coveralls@^3.0.1: 112 | version "3.0.1" 113 | resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.0.1.tgz#12e15914eaa29204e56869a5ece7b9e1492d2ae2" 114 | dependencies: 115 | js-yaml "^3.6.1" 116 | lcov-parse "^0.0.10" 117 | log-driver "^1.2.5" 118 | minimist "^1.2.0" 119 | request "^2.79.0" 120 | 121 | dashdash@^1.12.0: 122 | version "1.14.1" 123 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 124 | dependencies: 125 | assert-plus "^1.0.0" 126 | 127 | debug@3.1.0: 128 | version "3.1.0" 129 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 130 | dependencies: 131 | ms "2.0.0" 132 | 133 | deep-is@~0.1.3: 134 | version "0.1.3" 135 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" 136 | 137 | delayed-stream@~1.0.0: 138 | version "1.0.0" 139 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 140 | 141 | diff@3.5.0: 142 | version "3.5.0" 143 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" 144 | 145 | ecc-jsbn@~0.1.1: 146 | version "0.1.1" 147 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" 148 | dependencies: 149 | jsbn "~0.1.0" 150 | 151 | escape-string-regexp@1.0.5: 152 | version "1.0.5" 153 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 154 | 155 | escodegen@1.8.x: 156 | version "1.8.1" 157 | resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" 158 | dependencies: 159 | esprima "^2.7.1" 160 | estraverse "^1.9.1" 161 | esutils "^2.0.2" 162 | optionator "^0.8.1" 163 | optionalDependencies: 164 | source-map "~0.2.0" 165 | 166 | esprima@2.7.x, esprima@^2.7.1: 167 | version "2.7.3" 168 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" 169 | 170 | esprima@^4.0.0: 171 | version "4.0.1" 172 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 173 | 174 | estraverse@^1.9.1: 175 | version "1.9.3" 176 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" 177 | 178 | esutils@^2.0.2: 179 | version "2.0.2" 180 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" 181 | 182 | extend@~3.0.1: 183 | version "3.0.2" 184 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" 185 | 186 | extsprintf@1.3.0: 187 | version "1.3.0" 188 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" 189 | 190 | extsprintf@^1.2.0: 191 | version "1.4.0" 192 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" 193 | 194 | fast-deep-equal@^1.0.0: 195 | version "1.1.0" 196 | resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" 197 | 198 | fast-json-stable-stringify@^2.0.0: 199 | version "2.0.0" 200 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" 201 | 202 | fast-levenshtein@~2.0.4: 203 | version "2.0.6" 204 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 205 | 206 | forever-agent@~0.6.1: 207 | version "0.6.1" 208 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 209 | 210 | form-data@~2.3.1: 211 | version "2.3.2" 212 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099" 213 | dependencies: 214 | asynckit "^0.4.0" 215 | combined-stream "1.0.6" 216 | mime-types "^2.1.12" 217 | 218 | fs.realpath@^1.0.0: 219 | version "1.0.0" 220 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 221 | 222 | getpass@^0.1.1: 223 | version "0.1.7" 224 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 225 | dependencies: 226 | assert-plus "^1.0.0" 227 | 228 | glob@7.1.2: 229 | version "7.1.2" 230 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 231 | dependencies: 232 | fs.realpath "^1.0.0" 233 | inflight "^1.0.4" 234 | inherits "2" 235 | minimatch "^3.0.4" 236 | once "^1.3.0" 237 | path-is-absolute "^1.0.0" 238 | 239 | glob@^5.0.15: 240 | version "5.0.15" 241 | resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" 242 | dependencies: 243 | inflight "^1.0.4" 244 | inherits "2" 245 | minimatch "2 || 3" 246 | once "^1.3.0" 247 | path-is-absolute "^1.0.0" 248 | 249 | growl@1.10.5: 250 | version "1.10.5" 251 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 252 | 253 | handlebars@^4.0.1: 254 | version "4.4.3" 255 | resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.4.3.tgz#180bae52c1d0e9ec0c15d7e82a4362d662762f6e" 256 | dependencies: 257 | neo-async "^2.6.0" 258 | optimist "^0.6.1" 259 | source-map "^0.6.1" 260 | optionalDependencies: 261 | uglify-js "^3.1.4" 262 | 263 | har-schema@^2.0.0: 264 | version "2.0.0" 265 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" 266 | 267 | har-validator@~5.0.3: 268 | version "5.0.3" 269 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" 270 | dependencies: 271 | ajv "^5.1.0" 272 | har-schema "^2.0.0" 273 | 274 | has-flag@^1.0.0: 275 | version "1.0.0" 276 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" 277 | 278 | has-flag@^3.0.0: 279 | version "3.0.0" 280 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 281 | 282 | he@1.1.1: 283 | version "1.1.1" 284 | resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" 285 | 286 | http-signature@~1.2.0: 287 | version "1.2.0" 288 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" 289 | dependencies: 290 | assert-plus "^1.0.0" 291 | jsprim "^1.2.2" 292 | sshpk "^1.7.0" 293 | 294 | inflight@^1.0.4: 295 | version "1.0.6" 296 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 297 | dependencies: 298 | once "^1.3.0" 299 | wrappy "1" 300 | 301 | inherits@2: 302 | version "2.0.3" 303 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 304 | 305 | is-typedarray@~1.0.0: 306 | version "1.0.0" 307 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 308 | 309 | isexe@^2.0.0: 310 | version "2.0.0" 311 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 312 | 313 | isstream@~0.1.2: 314 | version "0.1.2" 315 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 316 | 317 | istanbul@^0.4.5: 318 | version "0.4.5" 319 | resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" 320 | dependencies: 321 | abbrev "1.0.x" 322 | async "1.x" 323 | escodegen "1.8.x" 324 | esprima "2.7.x" 325 | glob "^5.0.15" 326 | handlebars "^4.0.1" 327 | js-yaml "3.x" 328 | mkdirp "0.5.x" 329 | nopt "3.x" 330 | once "1.x" 331 | resolve "1.1.x" 332 | supports-color "^3.1.0" 333 | which "^1.1.1" 334 | wordwrap "^1.0.0" 335 | 336 | js-yaml@3.x, js-yaml@^3.6.1: 337 | version "3.13.1" 338 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 339 | dependencies: 340 | argparse "^1.0.7" 341 | esprima "^4.0.0" 342 | 343 | jsbn@~0.1.0: 344 | version "0.1.1" 345 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 346 | 347 | json-schema-traverse@^0.3.0: 348 | version "0.3.1" 349 | resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" 350 | 351 | json-schema@0.2.3: 352 | version "0.2.3" 353 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 354 | 355 | json-stringify-safe@~5.0.1: 356 | version "5.0.1" 357 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 358 | 359 | jsprim@^1.2.2: 360 | version "1.4.1" 361 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" 362 | dependencies: 363 | assert-plus "1.0.0" 364 | extsprintf "1.3.0" 365 | json-schema "0.2.3" 366 | verror "1.10.0" 367 | 368 | lcov-parse@^0.0.10: 369 | version "0.0.10" 370 | resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" 371 | 372 | levn@~0.3.0: 373 | version "0.3.0" 374 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 375 | dependencies: 376 | prelude-ls "~1.1.2" 377 | type-check "~0.3.2" 378 | 379 | log-driver@^1.2.5: 380 | version "1.2.7" 381 | resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" 382 | 383 | mime-db@~1.33.0: 384 | version "1.33.0" 385 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" 386 | 387 | mime-types@^2.1.12, mime-types@~2.1.17: 388 | version "2.1.18" 389 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8" 390 | dependencies: 391 | mime-db "~1.33.0" 392 | 393 | "minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.4: 394 | version "3.0.4" 395 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 396 | dependencies: 397 | brace-expansion "^1.1.7" 398 | 399 | minimist@0.0.8: 400 | version "0.0.8" 401 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 402 | 403 | minimist@^1.2.0: 404 | version "1.2.0" 405 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 406 | 407 | minimist@~0.0.1: 408 | version "0.0.10" 409 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" 410 | 411 | mkdirp@0.5.1, mkdirp@0.5.x: 412 | version "0.5.1" 413 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 414 | dependencies: 415 | minimist "0.0.8" 416 | 417 | mocha@^5.2.0: 418 | version "5.2.0" 419 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.2.0.tgz#6d8ae508f59167f940f2b5b3c4a612ae50c90ae6" 420 | dependencies: 421 | browser-stdout "1.3.1" 422 | commander "2.15.1" 423 | debug "3.1.0" 424 | diff "3.5.0" 425 | escape-string-regexp "1.0.5" 426 | glob "7.1.2" 427 | growl "1.10.5" 428 | he "1.1.1" 429 | minimatch "3.0.4" 430 | mkdirp "0.5.1" 431 | supports-color "5.4.0" 432 | 433 | ms@2.0.0: 434 | version "2.0.0" 435 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 436 | 437 | neo-async@^2.6.0: 438 | version "2.6.1" 439 | resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" 440 | 441 | nopt@3.x: 442 | version "3.0.6" 443 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" 444 | dependencies: 445 | abbrev "1" 446 | 447 | oauth-sign@~0.8.2: 448 | version "0.8.2" 449 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" 450 | 451 | once@1.x, once@^1.3.0: 452 | version "1.4.0" 453 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 454 | dependencies: 455 | wrappy "1" 456 | 457 | optimist@^0.6.1: 458 | version "0.6.1" 459 | resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" 460 | dependencies: 461 | minimist "~0.0.1" 462 | wordwrap "~0.0.2" 463 | 464 | optionator@^0.8.1: 465 | version "0.8.2" 466 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" 467 | dependencies: 468 | deep-is "~0.1.3" 469 | fast-levenshtein "~2.0.4" 470 | levn "~0.3.0" 471 | prelude-ls "~1.1.2" 472 | type-check "~0.3.2" 473 | wordwrap "~1.0.0" 474 | 475 | path-is-absolute@^1.0.0: 476 | version "1.0.1" 477 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 478 | 479 | performance-now@^2.1.0: 480 | version "2.1.0" 481 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" 482 | 483 | prelude-ls@~1.1.2: 484 | version "1.1.2" 485 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 486 | 487 | punycode@^1.4.1: 488 | version "1.4.1" 489 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 490 | 491 | qs@~6.5.1: 492 | version "6.5.2" 493 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" 494 | 495 | request@^2.79.0: 496 | version "2.87.0" 497 | resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e" 498 | dependencies: 499 | aws-sign2 "~0.7.0" 500 | aws4 "^1.6.0" 501 | caseless "~0.12.0" 502 | combined-stream "~1.0.5" 503 | extend "~3.0.1" 504 | forever-agent "~0.6.1" 505 | form-data "~2.3.1" 506 | har-validator "~5.0.3" 507 | http-signature "~1.2.0" 508 | is-typedarray "~1.0.0" 509 | isstream "~0.1.2" 510 | json-stringify-safe "~5.0.1" 511 | mime-types "~2.1.17" 512 | oauth-sign "~0.8.2" 513 | performance-now "^2.1.0" 514 | qs "~6.5.1" 515 | safe-buffer "^5.1.1" 516 | tough-cookie "~2.3.3" 517 | tunnel-agent "^0.6.0" 518 | uuid "^3.1.0" 519 | 520 | resolve@1.1.x: 521 | version "1.1.7" 522 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" 523 | 524 | safe-buffer@^5.0.1, safe-buffer@^5.1.1: 525 | version "5.1.2" 526 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 527 | 528 | safer-buffer@^2.0.2: 529 | version "2.1.2" 530 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 531 | 532 | source-map@^0.6.1, source-map@~0.6.1: 533 | version "0.6.1" 534 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 535 | 536 | source-map@~0.2.0: 537 | version "0.2.0" 538 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" 539 | dependencies: 540 | amdefine ">=0.0.4" 541 | 542 | sprintf-js@~1.0.2: 543 | version "1.0.3" 544 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 545 | 546 | sshpk@^1.7.0: 547 | version "1.14.2" 548 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.14.2.tgz#c6fc61648a3d9c4e764fd3fcdf4ea105e492ba98" 549 | dependencies: 550 | asn1 "~0.2.3" 551 | assert-plus "^1.0.0" 552 | dashdash "^1.12.0" 553 | getpass "^0.1.1" 554 | safer-buffer "^2.0.2" 555 | optionalDependencies: 556 | bcrypt-pbkdf "^1.0.0" 557 | ecc-jsbn "~0.1.1" 558 | jsbn "~0.1.0" 559 | tweetnacl "~0.14.0" 560 | 561 | supports-color@5.4.0: 562 | version "5.4.0" 563 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" 564 | dependencies: 565 | has-flag "^3.0.0" 566 | 567 | supports-color@^3.1.0: 568 | version "3.2.3" 569 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" 570 | dependencies: 571 | has-flag "^1.0.0" 572 | 573 | tough-cookie@~2.3.3: 574 | version "2.3.4" 575 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655" 576 | dependencies: 577 | punycode "^1.4.1" 578 | 579 | tunnel-agent@^0.6.0: 580 | version "0.6.0" 581 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 582 | dependencies: 583 | safe-buffer "^5.0.1" 584 | 585 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 586 | version "0.14.5" 587 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 588 | 589 | type-check@~0.3.2: 590 | version "0.3.2" 591 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 592 | dependencies: 593 | prelude-ls "~1.1.2" 594 | 595 | uglify-js@^3.1.4: 596 | version "3.6.1" 597 | resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.1.tgz#ae7688c50e1bdcf2f70a0e162410003cf9798311" 598 | dependencies: 599 | commander "2.20.0" 600 | source-map "~0.6.1" 601 | 602 | uuid@^3.1.0: 603 | version "3.2.1" 604 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" 605 | 606 | verror@1.10.0: 607 | version "1.10.0" 608 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" 609 | dependencies: 610 | assert-plus "^1.0.0" 611 | core-util-is "1.0.2" 612 | extsprintf "^1.2.0" 613 | 614 | which@^1.1.1: 615 | version "1.3.1" 616 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 617 | dependencies: 618 | isexe "^2.0.0" 619 | 620 | wordwrap@^1.0.0, wordwrap@~1.0.0: 621 | version "1.0.0" 622 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" 623 | 624 | wordwrap@~0.0.2: 625 | version "0.0.3" 626 | resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" 627 | 628 | wrappy@1: 629 | version "1.0.2" 630 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 631 | --------------------------------------------------------------------------------