├── .eslintrc ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── context.js ├── package-lock.json ├── package.json └── test ├── async-context.tap.js ├── async-no-run-queue-multiple.tap.js ├── bind-emitter.tap.js ├── bind.tap.js ├── crypto.tap.js ├── dns.tap.js ├── error-handling.tap.js ├── fs.tap.js ├── interleave-contexts.tap.js ├── monkeypatching.tap.js ├── namespaces.tap.js ├── nesting.tap.js ├── net-events.tap.js ├── promises.tap.js ├── proper-exit.tap.js ├── run-and-return.tap.js ├── simple.tap.js ├── timers.tap.js ├── tracer-scenarios.tap.js └── zlib.tap.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env" : { 3 | "node" : true 4 | }, 5 | "rules" : { 6 | "curly" : 0, 7 | "no-lonely-if" : 1, 8 | "no-mixed-requires" : 0, 9 | "no-underscore-dangle" : 0, 10 | "no-unused-vars" : [2, {"vars" : "all", "args" : "after-used"}], 11 | "no-use-before-define" : [2, "nofunc"], 12 | "quotes" : 0, 13 | "semi" : [2, "always"], 14 | "space-after-keywords" : 1, 15 | "space-infix-ops" : 0, 16 | "strict" : 0, 17 | "max-len" : [1, 90, 2] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | script: 2 | - "npm test" 3 | 4 | language: node_js 5 | 6 | node_js: 7 | - "0.10" 8 | - "0.12" 9 | - "4" 10 | - "6" 11 | - "8" 12 | - "9" 13 | 14 | sudo: false 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### v3.1.0 (2014-07-28): 2 | 3 | * Updated to use `async-listener@0.4.7` to pick up bug fixes. 4 | 5 | ### v3.0.0 (2013-12-14): 6 | 7 | * Removed the notion of a "default" or "global" context per namespace. It only 8 | existed to create a simpler interface for developing and testing the module, 9 | and created the potential for nasty information disclosure bugs (see [issue 10 | #14](https://github.com/othiym23/node-continuation-local-storage/issues/14) 11 | for details). This is potentially a breaking change, if you're depending on 12 | the global context, so semver says we have to bump the major version. 13 | * Added this changelog. 14 | 15 | ### v2.6.2 (2013-12-07): 16 | 17 | * `async-listener` and `emitter-listener` dependency refresh. 18 | 19 | ### v2.6.1 (2013-11-29): 20 | 21 | * `emitter-listener` has been extracted from `shimmer` into a standalone 22 | module for `namespace.bindEmitter()`. 23 | 24 | ### v2.6.0 (2013-11-27): 25 | 26 | * When an error is thrown in a CLS-bound continuation chain, attach the active 27 | context for the namespace to which the chain is bound. This is necessary 28 | because CLS and asyncListeners actually do too good a job of cleaning up 29 | after errors, and so they don't escape the continuation chain. New Relic 30 | needs the context so it can get the transaction active when the error 31 | happened for error tracing. 32 | 33 | ### v2.5.2 (2013-10-30): 34 | 35 | * `async-listener` dependency refresh for better support of node 0.8.0 - 0.8.3. 36 | 37 | ### v2.5.1 (2013-10-27): 38 | 39 | * `async-listener` dependency refresh. 40 | 41 | ### v2.5.0 (2013-10-27): 42 | 43 | * Relax the requirement that CLS contexts be pushed and popped from a stack, 44 | instead treating them as a set. This allows context interleaving (i.e. 45 | using the lower-level `namespace.enter()` and `namespace.exit()` API without 46 | any strict ordering dependencies). Everything works, but this still makes me 47 | a little uneasy. 48 | * EEs can now be bound to multiple namespaces, although this is likely to be 49 | slow. 50 | 51 | ### v2.4.4 (2013-10-27): 52 | 53 | * Even if you use an EE bound to a namespace outside a continuation chain, it 54 | shouldn't explode. 55 | 56 | ### v2.4.3 (2013-10-16): 57 | 58 | * `async-listener` dependency refresh. 59 | 60 | ### v2.4.2 (2013-10-13): 61 | 62 | * More tweaks for `async-listener` error handlers (just a dependency refresh). 63 | 64 | ### v2.4.1 (2013-10-12): 65 | 66 | * `async-listener` error listeners have gotten lots of tweaks. Update to newest 67 | API. 68 | * Only exit namespace context on error if a continuation chain is active. 69 | 70 | ### v2.4.0 (2013-10-11): 71 | 72 | * `async-listener` now supports error listeners. Update to newest API. 73 | * Namespace context should be exited on asynchronous errors. 74 | 75 | ### v2.3.4 (2013-10-03): 76 | 77 | * When EEs are in the middle of emitting, make sure that calls to 78 | `emitter.removeListener` are testing against non-monkeypatched versions of 79 | the event handlers (necessary so certain Connect middleware functions, such 80 | as `connect.limit`, run correctly). 81 | 82 | ### v2.3.3 (2013-10-02): 83 | 84 | * Ensure handler rebinding gets called even in case of errors. 85 | * Be consistent about making sure contexts are kept in a sane state when errors 86 | are thrown in EEs. 87 | 88 | ### v2.3.2 (2013-10-02): 89 | 90 | * Guard `on` / `addListener` remonkeypatching in `namespace.bindEmitter()` so 91 | that `shimmer` is only called to rebind if the monkeypatched versions have 92 | actually been replaced. 93 | * Don't try to call emit if there are no listeners on a bound EE. 94 | * Don't use `setImmediate` in tests, because it's not available in Node 0.8.x. 95 | 96 | ### v2.3.1 (2013-10-01): 97 | 98 | * Update to newest version of `async-listener`. 99 | * Fix typo. 100 | 101 | ### v2.3.0 (2013-09-30): 102 | 103 | * EventEmitters can now be bound to CLS namespaces. Because EEs act as coupling 104 | points between asynchronous domains, it's necessary for the EE binding to 105 | capture the CLS context both when the listener is added, and when a matching 106 | handler is firing because of a matching event being emitted. 107 | 108 | ### v2.2.1 (2013-09-30): 109 | 110 | * More tweaks to conform with `asyncListener` API changes. 111 | * Many more test cases to ensure `asyncListener` stuff is working with Node 112 | 0.8.x. 113 | 114 | ### v2.2.0 (2013-09-26): 115 | 116 | * Square up with latest `async-listener` / node PR #6011 changes. 117 | 118 | ### v2.1.2 (2013-09-09): 119 | 120 | * Document `namespace.createContext()`. 121 | * Fix issue where a value was *always* being returned from `namespace.run()`, 122 | even on error. 123 | 124 | ### v2.1.1 (2013-09-03): 125 | 126 | * Clean up minor typo in docs. 127 | 128 | ### v2.1.0 (2013-09-03): 129 | 130 | * Incorporate documentation from failed CLS PR. 131 | * `namespace.bind()` now also always exits the domain, even on error. 132 | * Namespaces can be destroyed. 133 | * `cls.reset()` allows tests to nuke all existing namespaces (use with care 134 | obviously). 135 | 136 | ### v2.0.0 (2013-09-01): 137 | 138 | * Use `async-listener` polyfill instead of `cls-glue`. 139 | * Incorporate tests from `cls-glue`. 140 | 141 | ### v1.1.1 (2013-09-01): 142 | 143 | * Namespace exits context even on error. 144 | 145 | ### v1.1.0 (2013-07-30): 146 | 147 | * Split createContext so it's part of the namespace API. 148 | * Tweak error message to be more informative. 149 | 150 | ### v1.0.1 (2013-07-25): 151 | 152 | * Correct Tim's email address. 153 | 154 | ### v1.0.0 (2013-07-25): 155 | 156 | * Each application of CLS is allocated its own "namespace", which bind data to 157 | continuation chains, either using `.run()` or `.bind()` to create a new 158 | nested context. These nested contexts are prototype chains that point back to 159 | a "default" / "global" context, with the default context for each namespace 160 | being a prototype-free "data bag" created with `Object.create(null)`. 161 | 162 | ### v0.1.1 (2013-05-03): 163 | 164 | * Document progress thus far. 165 | 166 | ### v0.1.0 (2013-05-03): 167 | 168 | * First attempt: basic API, docs, and tests. 169 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2016, Forrest L Norvell 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![NPM](https://nodei.co/npm/continuation-local-storage.png?downloads=true&stars=true)](https://nodei.co/npm/continuation-local-storage/) 2 | 3 | # Continuation-Local Storage 4 | 5 | Continuation-local storage works like thread-local storage in threaded 6 | programming, but is based on chains of Node-style callbacks instead of threads. 7 | The standard Node convention of functions calling functions is very similar to 8 | something called ["continuation-passing style"][cps] in functional programming, 9 | and the name comes from the way this module allows you to set and get values 10 | that are scoped to the lifetime of these chains of function calls. 11 | 12 | Suppose you're writing a module that fetches a user and adds it to a session 13 | before calling a function passed in by a user to continue execution: 14 | 15 | ```javascript 16 | // setup.js 17 | 18 | var createNamespace = require('continuation-local-storage').createNamespace; 19 | var session = createNamespace('my session'); 20 | 21 | var db = require('./lib/db.js'); 22 | 23 | function start(options, next) { 24 | db.fetchUserById(options.id, function (error, user) { 25 | if (error) return next(error); 26 | 27 | session.set('user', user); 28 | 29 | next(); 30 | }); 31 | } 32 | ``` 33 | 34 | Later on in the process of turning that user's data into an HTML page, you call 35 | another function (maybe defined in another module entirely) that wants to fetch 36 | the value you set earlier: 37 | 38 | ```javascript 39 | // send_response.js 40 | 41 | var getNamespace = require('continuation-local-storage').getNamespace; 42 | var session = getNamespace('my session'); 43 | 44 | var render = require('./lib/render.js') 45 | 46 | function finish(response) { 47 | var user = session.get('user'); 48 | render({user: user}).pipe(response); 49 | } 50 | ``` 51 | 52 | When you set values in continuation-local storage, those values are accessible 53 | until all functions called from the original function – synchronously or 54 | asynchronously – have finished executing. This includes callbacks passed to 55 | `process.nextTick` and the [timer functions][] ([setImmediate][], 56 | [setTimeout][], and [setInterval][]), as well as callbacks passed to 57 | asynchronous functions that call native functions (such as those exported from 58 | the `fs`, `dns`, `zlib` and `crypto` modules). 59 | 60 | A simple rule of thumb is anywhere where you might have set a property on the 61 | `request` or `response` objects in an HTTP handler, you can (and should) now 62 | use continuation-local storage. This API is designed to allow you extend the 63 | scope of a variable across a sequence of function calls, but with values 64 | specific to each sequence of calls. 65 | 66 | Values are grouped into namespaces, created with `createNamespace()`. Sets of 67 | function calls are grouped together by calling them within the function passed 68 | to `.run()` on the namespace object. Calls to `.run()` can be nested, and each 69 | nested context this creates has its own copy of the set of values from the 70 | parent context. When a function is making multiple asynchronous calls, this 71 | allows each child call to get, set, and pass along its own context without 72 | overwriting the parent's. 73 | 74 | A simple, annotated example of how this nesting behaves: 75 | 76 | ```javascript 77 | var createNamespace = require('continuation-local-storage').createNamespace; 78 | 79 | var writer = createNamespace('writer'); 80 | writer.run(function () { 81 | writer.set('value', 0); 82 | 83 | requestHandler(); 84 | }); 85 | 86 | function requestHandler() { 87 | writer.run(function(outer) { 88 | // writer.get('value') returns 0 89 | // outer.value is 0 90 | writer.set('value', 1); 91 | // writer.get('value') returns 1 92 | // outer.value is 1 93 | process.nextTick(function() { 94 | // writer.get('value') returns 1 95 | // outer.value is 1 96 | writer.run(function(inner) { 97 | // writer.get('value') returns 1 98 | // outer.value is 1 99 | // inner.value is 1 100 | writer.set('value', 2); 101 | // writer.get('value') returns 2 102 | // outer.value is 1 103 | // inner.value is 2 104 | }); 105 | }); 106 | }); 107 | 108 | setTimeout(function() { 109 | // runs with the default context, because nested contexts have ended 110 | console.log(writer.get('value')); // prints 0 111 | }, 1000); 112 | } 113 | ``` 114 | 115 | ## cls.createNamespace(name) 116 | 117 | * return: {Namespace} 118 | 119 | Each application wanting to use continuation-local values should create its own 120 | namespace. Reading from (or, more significantly, writing to) namespaces that 121 | don't belong to you is a faux pas. 122 | 123 | ## cls.getNamespace(name) 124 | 125 | * return: {Namespace} 126 | 127 | Look up an existing namespace. 128 | 129 | ## cls.destroyNamespace(name) 130 | 131 | Dispose of an existing namespace. WARNING: be sure to dispose of any references 132 | to destroyed namespaces in your old code, as contexts associated with them will 133 | no longer be propagated. 134 | 135 | ## cls.reset() 136 | 137 | Completely reset all continuation-local storage namespaces. WARNING: while this 138 | will stop the propagation of values in any existing namespaces, if there are 139 | remaining references to those namespaces in code, the associated storage will 140 | still be reachable, even though the associated state is no longer being updated. 141 | Make sure you clean up any references to destroyed namespaces yourself. 142 | 143 | ## process.namespaces 144 | 145 | * return: dictionary of {Namespace} objects 146 | 147 | Continuation-local storage has a performance cost, and so it isn't enabled 148 | until the module is loaded for the first time. Once the module is loaded, the 149 | current set of namespaces is available in `process.namespaces`, so library code 150 | that wants to use continuation-local storage only when it's active should test 151 | for the existence of `process.namespaces`. 152 | 153 | ## Class: Namespace 154 | 155 | Application-specific namespaces group values local to the set of functions 156 | whose calls originate from a callback passed to `namespace.run()` or 157 | `namespace.bind()`. 158 | 159 | ### namespace.active 160 | 161 | * return: the currently active context on a namespace 162 | 163 | ### namespace.set(key, value) 164 | 165 | * return: `value` 166 | 167 | Set a value on the current continuation context. Must be set within an active 168 | continuation chain started with `namespace.run()` or `namespace.bind()`. 169 | 170 | ### namespace.get(key) 171 | 172 | * return: the requested value, or `undefined` 173 | 174 | Look up a value on the current continuation context. Recursively searches from 175 | the innermost to outermost nested continuation context for a value associated 176 | with a given key. Must be set within an active continuation chain started with 177 | `namespace.run()` or `namespace.bind()`. 178 | 179 | ### namespace.run(callback) 180 | 181 | * return: the context associated with that callback 182 | 183 | Create a new context on which values can be set or read. Run all the functions 184 | that are called (either directly, or indirectly through asynchronous functions 185 | that take callbacks themselves) from the provided callback within the scope of 186 | that namespace. The new context is passed as an argument to the callback 187 | when it's called. 188 | 189 | ### namespace.runAndReturn(callback) 190 | 191 | * return: the return value of the callback 192 | 193 | Create a new context on which values can be set or read. Run all the functions 194 | that are called (either directly, or indirectly through asynchronous functions 195 | that take callbacks themselves) from the provided callback within the scope of 196 | that namespace. The new context is passed as an argument to the callback 197 | when it's called. 198 | 199 | Same as `namespace.run()` but returns the return value of the callback rather 200 | than the context. 201 | 202 | ### namespace.bind(callback, [context]) 203 | 204 | * return: a callback wrapped up in a context closure 205 | 206 | Bind a function to the specified namespace. Works analogously to 207 | `Function.bind()` or `domain.bind()`. If context is omitted, it will default to 208 | the currently active context in the namespace, or create a new context if none 209 | is currently defined. 210 | 211 | ### namespace.bindEmitter(emitter) 212 | 213 | Bind an EventEmitter to a namespace. Operates similarly to `domain.add`, with a 214 | less generic name and the additional caveat that unlike domains, namespaces 215 | never implicitly bind EventEmitters to themselves when they're created within 216 | the context of an active namespace. 217 | 218 | The most likely time you'd want to use this is when you're using Express or 219 | Connect and want to make sure your middleware execution plays nice with CLS, or 220 | are doing other things with HTTP listeners: 221 | 222 | ```javascript 223 | http.createServer(function (req, res) { 224 | writer.bindEmitter(req); 225 | writer.bindEmitter(res); 226 | 227 | // do other stuff, some of which is asynchronous 228 | }); 229 | ``` 230 | 231 | ### namespace.createContext() 232 | 233 | * return: a context cloned from the currently active context 234 | 235 | Use this with `namespace.bind()`, if you want to have a fresh context at invocation time, 236 | as opposed to binding time: 237 | 238 | ```javascript 239 | function doSomething(p) { 240 | console.log("%s = %s", p, ns.get(p)); 241 | } 242 | 243 | function bindLater(callback) { 244 | return writer.bind(callback, writer.createContext()); 245 | } 246 | 247 | setInterval(function () { 248 | var bound = bindLater(doSomething); 249 | bound('test'); 250 | }, 100); 251 | ``` 252 | 253 | ## context 254 | 255 | A context is a plain object created using the enclosing context as its prototype. 256 | 257 | # copyright & license 258 | 259 | See [LICENSE](https://github.com/othiym23/node-continuation-local-storage/blob/master/LICENSE) 260 | for the details of the BSD 2-clause "simplified" license used by 261 | `continuation-local-storage`. This package was developed in 2012-2013 (and is 262 | maintained now) by Forrest L Norvell, [@othiym23](https://github.com/othiym23), 263 | with considerable help from Timothy Caswell, 264 | [@creationix](https://github.com/creationix), working for The Node Firm. This 265 | work was underwritten by New Relic for use in their Node.js instrumentation 266 | agent, so maybe give that a look if you have some Node.js 267 | performance-monitoring needs. 268 | 269 | [timer functions]: https://nodejs.org/api/timers.html 270 | [setImmediate]: https://nodejs.org/api/timers.html#timers_setimmediate_callback_arg 271 | [setTimeout]: https://nodejs.org/api/timers.html#timers_settimeout_callback_delay_arg 272 | [setInterval]: https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_arg 273 | [cps]: http://en.wikipedia.org/wiki/Continuation-passing_style 274 | -------------------------------------------------------------------------------- /context.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var wrapEmitter = require('emitter-listener'); 5 | 6 | /* 7 | * 8 | * CONSTANTS 9 | * 10 | */ 11 | var CONTEXTS_SYMBOL = 'cls@contexts'; 12 | var ERROR_SYMBOL = 'error@context'; 13 | 14 | // load polyfill if native support is unavailable 15 | if (!process.addAsyncListener) require('async-listener'); 16 | 17 | function Namespace(name) { 18 | this.name = name; 19 | // changed in 2.7: no default context 20 | this.active = null; 21 | this._set = []; 22 | this.id = null; 23 | } 24 | 25 | Namespace.prototype.set = function (key, value) { 26 | if (!this.active) { 27 | throw new Error("No context available. ns.run() or ns.bind() must be called first."); 28 | } 29 | 30 | this.active[key] = value; 31 | return value; 32 | }; 33 | 34 | Namespace.prototype.get = function (key) { 35 | if (!this.active) return undefined; 36 | 37 | return this.active[key]; 38 | }; 39 | 40 | Namespace.prototype.createContext = function () { 41 | return Object.create(this.active); 42 | }; 43 | 44 | Namespace.prototype.run = function (fn) { 45 | var context = this.createContext(); 46 | this.enter(context); 47 | try { 48 | fn(context); 49 | return context; 50 | } 51 | catch (exception) { 52 | if (exception) { 53 | exception[ERROR_SYMBOL] = context; 54 | } 55 | throw exception; 56 | } 57 | finally { 58 | this.exit(context); 59 | } 60 | }; 61 | 62 | Namespace.prototype.runAndReturn = function (fn) { 63 | var value; 64 | this.run(function (context) { 65 | value = fn(context); 66 | }); 67 | return value; 68 | }; 69 | 70 | Namespace.prototype.bind = function (fn, context) { 71 | if (!context) { 72 | if (!this.active) { 73 | context = this.createContext(); 74 | } 75 | else { 76 | context = this.active; 77 | } 78 | } 79 | 80 | var self = this; 81 | return function () { 82 | self.enter(context); 83 | try { 84 | return fn.apply(this, arguments); 85 | } 86 | catch (exception) { 87 | if (exception) { 88 | exception[ERROR_SYMBOL] = context; 89 | } 90 | throw exception; 91 | } 92 | finally { 93 | self.exit(context); 94 | } 95 | }; 96 | }; 97 | 98 | Namespace.prototype.enter = function (context) { 99 | assert.ok(context, "context must be provided for entering"); 100 | 101 | this._set.push(this.active); 102 | this.active = context; 103 | }; 104 | 105 | Namespace.prototype.exit = function (context) { 106 | assert.ok(context, "context must be provided for exiting"); 107 | 108 | // Fast path for most exits that are at the top of the stack 109 | if (this.active === context) { 110 | assert.ok(this._set.length, "can't remove top context"); 111 | this.active = this._set.pop(); 112 | return; 113 | } 114 | 115 | // Fast search in the stack using lastIndexOf 116 | var index = this._set.lastIndexOf(context); 117 | 118 | assert.ok(index >= 0, "context not currently entered; can't exit"); 119 | assert.ok(index, "can't remove top context"); 120 | 121 | this._set.splice(index, 1); 122 | }; 123 | 124 | Namespace.prototype.bindEmitter = function (emitter) { 125 | assert.ok(emitter.on && emitter.addListener && emitter.emit, "can only bind real EEs"); 126 | 127 | var namespace = this; 128 | var thisSymbol = 'context@' + this.name; 129 | 130 | // Capture the context active at the time the emitter is bound. 131 | function attach(listener) { 132 | if (!listener) return; 133 | if (!listener[CONTEXTS_SYMBOL]) listener[CONTEXTS_SYMBOL] = Object.create(null); 134 | 135 | listener[CONTEXTS_SYMBOL][thisSymbol] = { 136 | namespace : namespace, 137 | context : namespace.active 138 | }; 139 | } 140 | 141 | // At emit time, bind the listener within the correct context. 142 | function bind(unwrapped) { 143 | if (!(unwrapped && unwrapped[CONTEXTS_SYMBOL])) return unwrapped; 144 | 145 | var wrapped = unwrapped; 146 | var contexts = unwrapped[CONTEXTS_SYMBOL]; 147 | Object.keys(contexts).forEach(function (name) { 148 | var thunk = contexts[name]; 149 | wrapped = thunk.namespace.bind(wrapped, thunk.context); 150 | }); 151 | return wrapped; 152 | } 153 | 154 | wrapEmitter(emitter, attach, bind); 155 | }; 156 | 157 | /** 158 | * If an error comes out of a namespace, it will have a context attached to it. 159 | * This function knows how to find it. 160 | * 161 | * @param {Error} exception Possibly annotated error. 162 | */ 163 | Namespace.prototype.fromException = function (exception) { 164 | return exception[ERROR_SYMBOL]; 165 | }; 166 | 167 | function get(name) { 168 | return process.namespaces[name]; 169 | } 170 | 171 | function create(name) { 172 | assert.ok(name, "namespace must be given a name!"); 173 | 174 | var namespace = new Namespace(name); 175 | namespace.id = process.addAsyncListener({ 176 | create : function () { return namespace.active; }, 177 | before : function (context, storage) { if (storage) namespace.enter(storage); }, 178 | after : function (context, storage) { if (storage) namespace.exit(storage); }, 179 | error : function (storage) { if (storage) namespace.exit(storage); } 180 | }); 181 | 182 | process.namespaces[name] = namespace; 183 | return namespace; 184 | } 185 | 186 | function destroy(name) { 187 | var namespace = get(name); 188 | 189 | assert.ok(namespace, "can't delete nonexistent namespace!"); 190 | assert.ok(namespace.id, "don't assign to process.namespaces directly!"); 191 | 192 | process.removeAsyncListener(namespace.id); 193 | process.namespaces[name] = null; 194 | } 195 | 196 | function reset() { 197 | // must unregister async listeners 198 | if (process.namespaces) { 199 | Object.keys(process.namespaces).forEach(function (name) { 200 | destroy(name); 201 | }); 202 | } 203 | process.namespaces = Object.create(null); 204 | } 205 | if (!process.namespaces) reset(); // call immediately to set up 206 | 207 | module.exports = { 208 | getNamespace : get, 209 | createNamespace : create, 210 | destroyNamespace : destroy, 211 | reset : reset 212 | }; 213 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "continuation-local-storage", 3 | "version": "3.2.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ansi-regex": { 8 | "version": "2.1.1", 9 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 10 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 11 | "dev": true 12 | }, 13 | "ansi-styles": { 14 | "version": "2.2.1", 15 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", 16 | "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", 17 | "dev": true 18 | }, 19 | "argparse": { 20 | "version": "1.0.9", 21 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", 22 | "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", 23 | "dev": true, 24 | "requires": { 25 | "sprintf-js": "1.0.3" 26 | } 27 | }, 28 | "asn1": { 29 | "version": "0.2.3", 30 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", 31 | "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", 32 | "dev": true 33 | }, 34 | "assert-plus": { 35 | "version": "0.2.0", 36 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", 37 | "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", 38 | "dev": true 39 | }, 40 | "async-listener": { 41 | "version": "0.6.8", 42 | "resolved": "https://registry.npmjs.org/async-listener/-/async-listener-0.6.8.tgz", 43 | "integrity": "sha1-01Vu+QXVrXe1LlKzfWix2KAkgfU=", 44 | "requires": { 45 | "semver": "5.4.1", 46 | "shimmer": "1.2.0" 47 | } 48 | }, 49 | "asynckit": { 50 | "version": "0.4.0", 51 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 52 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 53 | "dev": true 54 | }, 55 | "aws-sign2": { 56 | "version": "0.6.0", 57 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", 58 | "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", 59 | "dev": true 60 | }, 61 | "aws4": { 62 | "version": "1.6.0", 63 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", 64 | "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", 65 | "dev": true 66 | }, 67 | "balanced-match": { 68 | "version": "1.0.0", 69 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 70 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 71 | "dev": true 72 | }, 73 | "bcrypt-pbkdf": { 74 | "version": "1.0.1", 75 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", 76 | "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", 77 | "dev": true, 78 | "optional": true, 79 | "requires": { 80 | "tweetnacl": "0.14.5" 81 | } 82 | }, 83 | "bind-obj-methods": { 84 | "version": "1.0.0", 85 | "resolved": "https://registry.npmjs.org/bind-obj-methods/-/bind-obj-methods-1.0.0.tgz", 86 | "integrity": "sha1-T1l5ysFXk633DkiBYeRj4gnKUJw=", 87 | "dev": true 88 | }, 89 | "bluebird": { 90 | "version": "3.5.1", 91 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", 92 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", 93 | "dev": true 94 | }, 95 | "boom": { 96 | "version": "2.10.1", 97 | "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", 98 | "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", 99 | "dev": true, 100 | "requires": { 101 | "hoek": "2.16.3" 102 | } 103 | }, 104 | "brace-expansion": { 105 | "version": "1.1.8", 106 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", 107 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", 108 | "dev": true, 109 | "requires": { 110 | "balanced-match": "1.0.0", 111 | "concat-map": "0.0.1" 112 | } 113 | }, 114 | "caseless": { 115 | "version": "0.11.0", 116 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", 117 | "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", 118 | "dev": true 119 | }, 120 | "chalk": { 121 | "version": "1.1.3", 122 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", 123 | "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", 124 | "dev": true, 125 | "requires": { 126 | "ansi-styles": "2.2.1", 127 | "escape-string-regexp": "1.0.5", 128 | "has-ansi": "2.0.0", 129 | "strip-ansi": "3.0.1", 130 | "supports-color": "2.0.0" 131 | } 132 | }, 133 | "clean-yaml-object": { 134 | "version": "0.1.0", 135 | "resolved": "https://registry.npmjs.org/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz", 136 | "integrity": "sha1-Y/sRDcLOGoTcIfbZM0h20BCui2g=", 137 | "dev": true 138 | }, 139 | "color-support": { 140 | "version": "1.1.3", 141 | "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", 142 | "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", 143 | "dev": true 144 | }, 145 | "combined-stream": { 146 | "version": "1.0.5", 147 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", 148 | "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", 149 | "dev": true, 150 | "requires": { 151 | "delayed-stream": "1.0.0" 152 | } 153 | }, 154 | "commander": { 155 | "version": "2.11.0", 156 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", 157 | "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", 158 | "dev": true 159 | }, 160 | "concat-map": { 161 | "version": "0.0.1", 162 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 163 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 164 | "dev": true 165 | }, 166 | "core-util-is": { 167 | "version": "1.0.2", 168 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 169 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 170 | "dev": true 171 | }, 172 | "coveralls": { 173 | "version": "2.13.3", 174 | "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.13.3.tgz", 175 | "integrity": "sha512-iiAmn+l1XqRwNLXhW8Rs5qHZRFMYp9ZIPjEOVRpC/c4so6Y/f4/lFi0FfR5B9cCqgyhkJ5cZmbvcVRfP8MHchw==", 176 | "dev": true, 177 | "requires": { 178 | "js-yaml": "3.6.1", 179 | "lcov-parse": "0.0.10", 180 | "log-driver": "1.2.5", 181 | "minimist": "1.2.0", 182 | "request": "2.79.0" 183 | }, 184 | "dependencies": { 185 | "js-yaml": { 186 | "version": "3.6.1", 187 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.6.1.tgz", 188 | "integrity": "sha1-bl/mfYsgXOTSL60Ft3geja3MSzA=", 189 | "dev": true, 190 | "requires": { 191 | "argparse": "1.0.9", 192 | "esprima": "2.7.3" 193 | } 194 | } 195 | } 196 | }, 197 | "cross-spawn": { 198 | "version": "4.0.2", 199 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", 200 | "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", 201 | "dev": true, 202 | "requires": { 203 | "lru-cache": "4.1.1", 204 | "which": "1.3.0" 205 | } 206 | }, 207 | "cryptiles": { 208 | "version": "2.0.5", 209 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", 210 | "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", 211 | "dev": true, 212 | "requires": { 213 | "boom": "2.10.1" 214 | } 215 | }, 216 | "dashdash": { 217 | "version": "1.14.1", 218 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 219 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 220 | "dev": true, 221 | "requires": { 222 | "assert-plus": "1.0.0" 223 | }, 224 | "dependencies": { 225 | "assert-plus": { 226 | "version": "1.0.0", 227 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 228 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 229 | "dev": true 230 | } 231 | } 232 | }, 233 | "debug": { 234 | "version": "2.6.9", 235 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 236 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 237 | "dev": true, 238 | "requires": { 239 | "ms": "2.0.0" 240 | } 241 | }, 242 | "delayed-stream": { 243 | "version": "1.0.0", 244 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 245 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 246 | "dev": true 247 | }, 248 | "diff": { 249 | "version": "1.4.0", 250 | "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz", 251 | "integrity": "sha1-fyjS657nsVqX79ic5j3P2qPMur8=", 252 | "dev": true 253 | }, 254 | "ecc-jsbn": { 255 | "version": "0.1.1", 256 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", 257 | "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", 258 | "dev": true, 259 | "optional": true, 260 | "requires": { 261 | "jsbn": "0.1.1" 262 | } 263 | }, 264 | "emitter-listener": { 265 | "version": "1.1.1", 266 | "resolved": "https://registry.npmjs.org/emitter-listener/-/emitter-listener-1.1.1.tgz", 267 | "integrity": "sha1-6Lu+gkS8jg0LTvcc0UKUx/JBx+w=", 268 | "requires": { 269 | "shimmer": "1.2.0" 270 | } 271 | }, 272 | "escape-string-regexp": { 273 | "version": "1.0.5", 274 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 275 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 276 | "dev": true 277 | }, 278 | "esprima": { 279 | "version": "2.7.3", 280 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", 281 | "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", 282 | "dev": true 283 | }, 284 | "events-to-array": { 285 | "version": "1.1.2", 286 | "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", 287 | "integrity": "sha1-LUH1Y+H+QA7Uli/hpNXGp1Od9/Y=", 288 | "dev": true 289 | }, 290 | "extend": { 291 | "version": "3.0.1", 292 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", 293 | "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", 294 | "dev": true 295 | }, 296 | "extsprintf": { 297 | "version": "1.3.0", 298 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 299 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", 300 | "dev": true 301 | }, 302 | "foreground-child": { 303 | "version": "1.5.6", 304 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", 305 | "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", 306 | "dev": true, 307 | "requires": { 308 | "cross-spawn": "4.0.2", 309 | "signal-exit": "3.0.2" 310 | } 311 | }, 312 | "forever-agent": { 313 | "version": "0.6.1", 314 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 315 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", 316 | "dev": true 317 | }, 318 | "form-data": { 319 | "version": "2.1.4", 320 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", 321 | "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", 322 | "dev": true, 323 | "requires": { 324 | "asynckit": "0.4.0", 325 | "combined-stream": "1.0.5", 326 | "mime-types": "2.1.17" 327 | } 328 | }, 329 | "fs-exists-cached": { 330 | "version": "1.0.0", 331 | "resolved": "https://registry.npmjs.org/fs-exists-cached/-/fs-exists-cached-1.0.0.tgz", 332 | "integrity": "sha1-zyVVTKBQ3EmuZla0HeQiWJidy84=", 333 | "dev": true 334 | }, 335 | "fs.realpath": { 336 | "version": "1.0.0", 337 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 338 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 339 | "dev": true 340 | }, 341 | "function-loop": { 342 | "version": "1.0.1", 343 | "resolved": "https://registry.npmjs.org/function-loop/-/function-loop-1.0.1.tgz", 344 | "integrity": "sha1-gHa7MF6OajzO7ikgdl8zDRkPNAw=", 345 | "dev": true 346 | }, 347 | "generate-function": { 348 | "version": "2.0.0", 349 | "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", 350 | "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", 351 | "dev": true 352 | }, 353 | "generate-object-property": { 354 | "version": "1.2.0", 355 | "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", 356 | "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", 357 | "dev": true, 358 | "requires": { 359 | "is-property": "1.0.2" 360 | } 361 | }, 362 | "getpass": { 363 | "version": "0.1.7", 364 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 365 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 366 | "dev": true, 367 | "requires": { 368 | "assert-plus": "1.0.0" 369 | }, 370 | "dependencies": { 371 | "assert-plus": { 372 | "version": "1.0.0", 373 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 374 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 375 | "dev": true 376 | } 377 | } 378 | }, 379 | "glob": { 380 | "version": "7.1.2", 381 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 382 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 383 | "dev": true, 384 | "requires": { 385 | "fs.realpath": "1.0.0", 386 | "inflight": "1.0.6", 387 | "inherits": "2.0.3", 388 | "minimatch": "3.0.4", 389 | "once": "1.4.0", 390 | "path-is-absolute": "1.0.1" 391 | } 392 | }, 393 | "har-validator": { 394 | "version": "2.0.6", 395 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", 396 | "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", 397 | "dev": true, 398 | "requires": { 399 | "chalk": "1.1.3", 400 | "commander": "2.11.0", 401 | "is-my-json-valid": "2.16.1", 402 | "pinkie-promise": "2.0.1" 403 | } 404 | }, 405 | "has-ansi": { 406 | "version": "2.0.0", 407 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 408 | "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", 409 | "dev": true, 410 | "requires": { 411 | "ansi-regex": "2.1.1" 412 | } 413 | }, 414 | "hawk": { 415 | "version": "3.1.3", 416 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", 417 | "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", 418 | "dev": true, 419 | "requires": { 420 | "boom": "2.10.1", 421 | "cryptiles": "2.0.5", 422 | "hoek": "2.16.3", 423 | "sntp": "1.0.9" 424 | } 425 | }, 426 | "hoek": { 427 | "version": "2.16.3", 428 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", 429 | "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", 430 | "dev": true 431 | }, 432 | "http-signature": { 433 | "version": "1.1.1", 434 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", 435 | "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", 436 | "dev": true, 437 | "requires": { 438 | "assert-plus": "0.2.0", 439 | "jsprim": "1.4.1", 440 | "sshpk": "1.13.1" 441 | } 442 | }, 443 | "inflight": { 444 | "version": "1.0.6", 445 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 446 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 447 | "dev": true, 448 | "requires": { 449 | "once": "1.4.0", 450 | "wrappy": "1.0.2" 451 | } 452 | }, 453 | "inherits": { 454 | "version": "2.0.3", 455 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 456 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 457 | "dev": true 458 | }, 459 | "is-my-json-valid": { 460 | "version": "2.16.1", 461 | "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz", 462 | "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", 463 | "dev": true, 464 | "requires": { 465 | "generate-function": "2.0.0", 466 | "generate-object-property": "1.2.0", 467 | "jsonpointer": "4.0.1", 468 | "xtend": "4.0.1" 469 | } 470 | }, 471 | "is-property": { 472 | "version": "1.0.2", 473 | "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", 474 | "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", 475 | "dev": true 476 | }, 477 | "is-typedarray": { 478 | "version": "1.0.0", 479 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 480 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", 481 | "dev": true 482 | }, 483 | "isarray": { 484 | "version": "1.0.0", 485 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 486 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 487 | "dev": true 488 | }, 489 | "isexe": { 490 | "version": "2.0.0", 491 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 492 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 493 | "dev": true 494 | }, 495 | "isstream": { 496 | "version": "0.1.2", 497 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 498 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", 499 | "dev": true 500 | }, 501 | "js-yaml": { 502 | "version": "3.10.0", 503 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", 504 | "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", 505 | "dev": true, 506 | "requires": { 507 | "argparse": "1.0.9", 508 | "esprima": "4.0.0" 509 | }, 510 | "dependencies": { 511 | "esprima": { 512 | "version": "4.0.0", 513 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", 514 | "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", 515 | "dev": true 516 | } 517 | } 518 | }, 519 | "jsbn": { 520 | "version": "0.1.1", 521 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 522 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", 523 | "dev": true, 524 | "optional": true 525 | }, 526 | "json-schema": { 527 | "version": "0.2.3", 528 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 529 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", 530 | "dev": true 531 | }, 532 | "json-stringify-safe": { 533 | "version": "5.0.1", 534 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 535 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", 536 | "dev": true 537 | }, 538 | "jsonpointer": { 539 | "version": "4.0.1", 540 | "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", 541 | "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", 542 | "dev": true 543 | }, 544 | "jsprim": { 545 | "version": "1.4.1", 546 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 547 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 548 | "dev": true, 549 | "requires": { 550 | "assert-plus": "1.0.0", 551 | "extsprintf": "1.3.0", 552 | "json-schema": "0.2.3", 553 | "verror": "1.10.0" 554 | }, 555 | "dependencies": { 556 | "assert-plus": { 557 | "version": "1.0.0", 558 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 559 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 560 | "dev": true 561 | } 562 | } 563 | }, 564 | "lcov-parse": { 565 | "version": "0.0.10", 566 | "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", 567 | "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", 568 | "dev": true 569 | }, 570 | "log-driver": { 571 | "version": "1.2.5", 572 | "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", 573 | "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=", 574 | "dev": true 575 | }, 576 | "lru-cache": { 577 | "version": "4.1.1", 578 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", 579 | "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", 580 | "dev": true, 581 | "requires": { 582 | "pseudomap": "1.0.2", 583 | "yallist": "2.1.2" 584 | } 585 | }, 586 | "mime-db": { 587 | "version": "1.30.0", 588 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", 589 | "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", 590 | "dev": true 591 | }, 592 | "mime-types": { 593 | "version": "2.1.17", 594 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", 595 | "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", 596 | "dev": true, 597 | "requires": { 598 | "mime-db": "1.30.0" 599 | } 600 | }, 601 | "minimatch": { 602 | "version": "3.0.4", 603 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 604 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 605 | "dev": true, 606 | "requires": { 607 | "brace-expansion": "1.1.8" 608 | } 609 | }, 610 | "minimist": { 611 | "version": "1.2.0", 612 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 613 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 614 | "dev": true 615 | }, 616 | "ms": { 617 | "version": "2.0.0", 618 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 619 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 620 | "dev": true 621 | }, 622 | "nyc": { 623 | "version": "11.3.0", 624 | "resolved": "https://registry.npmjs.org/nyc/-/nyc-11.3.0.tgz", 625 | "integrity": "sha512-oUu0WHt1k/JMIODvAYXX6C50Mupw2GO34P/Jdg2ty9xrLufBthHiKR2gf08aF+9S0abW1fl24R7iKRBXzibZmg==", 626 | "dev": true, 627 | "requires": { 628 | "archy": "1.0.0", 629 | "arrify": "1.0.1", 630 | "caching-transform": "1.0.1", 631 | "convert-source-map": "1.5.0", 632 | "debug-log": "1.0.1", 633 | "default-require-extensions": "1.0.0", 634 | "find-cache-dir": "0.1.1", 635 | "find-up": "2.1.0", 636 | "foreground-child": "1.5.6", 637 | "glob": "7.1.2", 638 | "istanbul-lib-coverage": "1.1.1", 639 | "istanbul-lib-hook": "1.1.0", 640 | "istanbul-lib-instrument": "1.9.1", 641 | "istanbul-lib-report": "1.1.2", 642 | "istanbul-lib-source-maps": "1.2.2", 643 | "istanbul-reports": "1.1.3", 644 | "md5-hex": "1.3.0", 645 | "merge-source-map": "1.0.4", 646 | "micromatch": "2.3.11", 647 | "mkdirp": "0.5.1", 648 | "resolve-from": "2.0.0", 649 | "rimraf": "2.6.2", 650 | "signal-exit": "3.0.2", 651 | "spawn-wrap": "1.3.8", 652 | "test-exclude": "4.1.1", 653 | "yargs": "10.0.3", 654 | "yargs-parser": "8.0.0" 655 | }, 656 | "dependencies": { 657 | "align-text": { 658 | "version": "0.1.4", 659 | "bundled": true, 660 | "dev": true, 661 | "requires": { 662 | "kind-of": "3.2.2", 663 | "longest": "1.0.1", 664 | "repeat-string": "1.6.1" 665 | } 666 | }, 667 | "amdefine": { 668 | "version": "1.0.1", 669 | "bundled": true, 670 | "dev": true 671 | }, 672 | "ansi-regex": { 673 | "version": "2.1.1", 674 | "bundled": true, 675 | "dev": true 676 | }, 677 | "ansi-styles": { 678 | "version": "2.2.1", 679 | "bundled": true, 680 | "dev": true 681 | }, 682 | "append-transform": { 683 | "version": "0.4.0", 684 | "bundled": true, 685 | "dev": true, 686 | "requires": { 687 | "default-require-extensions": "1.0.0" 688 | } 689 | }, 690 | "archy": { 691 | "version": "1.0.0", 692 | "bundled": true, 693 | "dev": true 694 | }, 695 | "arr-diff": { 696 | "version": "2.0.0", 697 | "bundled": true, 698 | "dev": true, 699 | "requires": { 700 | "arr-flatten": "1.1.0" 701 | } 702 | }, 703 | "arr-flatten": { 704 | "version": "1.1.0", 705 | "bundled": true, 706 | "dev": true 707 | }, 708 | "array-unique": { 709 | "version": "0.2.1", 710 | "bundled": true, 711 | "dev": true 712 | }, 713 | "arrify": { 714 | "version": "1.0.1", 715 | "bundled": true, 716 | "dev": true 717 | }, 718 | "async": { 719 | "version": "1.5.2", 720 | "bundled": true, 721 | "dev": true 722 | }, 723 | "babel-code-frame": { 724 | "version": "6.26.0", 725 | "bundled": true, 726 | "dev": true, 727 | "requires": { 728 | "chalk": "1.1.3", 729 | "esutils": "2.0.2", 730 | "js-tokens": "3.0.2" 731 | } 732 | }, 733 | "babel-generator": { 734 | "version": "6.26.0", 735 | "bundled": true, 736 | "dev": true, 737 | "requires": { 738 | "babel-messages": "6.23.0", 739 | "babel-runtime": "6.26.0", 740 | "babel-types": "6.26.0", 741 | "detect-indent": "4.0.0", 742 | "jsesc": "1.3.0", 743 | "lodash": "4.17.4", 744 | "source-map": "0.5.7", 745 | "trim-right": "1.0.1" 746 | } 747 | }, 748 | "babel-messages": { 749 | "version": "6.23.0", 750 | "bundled": true, 751 | "dev": true, 752 | "requires": { 753 | "babel-runtime": "6.26.0" 754 | } 755 | }, 756 | "babel-runtime": { 757 | "version": "6.26.0", 758 | "bundled": true, 759 | "dev": true, 760 | "requires": { 761 | "core-js": "2.5.1", 762 | "regenerator-runtime": "0.11.0" 763 | } 764 | }, 765 | "babel-template": { 766 | "version": "6.26.0", 767 | "bundled": true, 768 | "dev": true, 769 | "requires": { 770 | "babel-runtime": "6.26.0", 771 | "babel-traverse": "6.26.0", 772 | "babel-types": "6.26.0", 773 | "babylon": "6.18.0", 774 | "lodash": "4.17.4" 775 | } 776 | }, 777 | "babel-traverse": { 778 | "version": "6.26.0", 779 | "bundled": true, 780 | "dev": true, 781 | "requires": { 782 | "babel-code-frame": "6.26.0", 783 | "babel-messages": "6.23.0", 784 | "babel-runtime": "6.26.0", 785 | "babel-types": "6.26.0", 786 | "babylon": "6.18.0", 787 | "debug": "2.6.9", 788 | "globals": "9.18.0", 789 | "invariant": "2.2.2", 790 | "lodash": "4.17.4" 791 | } 792 | }, 793 | "babel-types": { 794 | "version": "6.26.0", 795 | "bundled": true, 796 | "dev": true, 797 | "requires": { 798 | "babel-runtime": "6.26.0", 799 | "esutils": "2.0.2", 800 | "lodash": "4.17.4", 801 | "to-fast-properties": "1.0.3" 802 | } 803 | }, 804 | "babylon": { 805 | "version": "6.18.0", 806 | "bundled": true, 807 | "dev": true 808 | }, 809 | "balanced-match": { 810 | "version": "1.0.0", 811 | "bundled": true, 812 | "dev": true 813 | }, 814 | "brace-expansion": { 815 | "version": "1.1.8", 816 | "bundled": true, 817 | "dev": true, 818 | "requires": { 819 | "balanced-match": "1.0.0", 820 | "concat-map": "0.0.1" 821 | } 822 | }, 823 | "braces": { 824 | "version": "1.8.5", 825 | "bundled": true, 826 | "dev": true, 827 | "requires": { 828 | "expand-range": "1.8.2", 829 | "preserve": "0.2.0", 830 | "repeat-element": "1.1.2" 831 | } 832 | }, 833 | "builtin-modules": { 834 | "version": "1.1.1", 835 | "bundled": true, 836 | "dev": true 837 | }, 838 | "caching-transform": { 839 | "version": "1.0.1", 840 | "bundled": true, 841 | "dev": true, 842 | "requires": { 843 | "md5-hex": "1.3.0", 844 | "mkdirp": "0.5.1", 845 | "write-file-atomic": "1.3.4" 846 | } 847 | }, 848 | "camelcase": { 849 | "version": "1.2.1", 850 | "bundled": true, 851 | "dev": true, 852 | "optional": true 853 | }, 854 | "center-align": { 855 | "version": "0.1.3", 856 | "bundled": true, 857 | "dev": true, 858 | "optional": true, 859 | "requires": { 860 | "align-text": "0.1.4", 861 | "lazy-cache": "1.0.4" 862 | } 863 | }, 864 | "chalk": { 865 | "version": "1.1.3", 866 | "bundled": true, 867 | "dev": true, 868 | "requires": { 869 | "ansi-styles": "2.2.1", 870 | "escape-string-regexp": "1.0.5", 871 | "has-ansi": "2.0.0", 872 | "strip-ansi": "3.0.1", 873 | "supports-color": "2.0.0" 874 | } 875 | }, 876 | "cliui": { 877 | "version": "2.1.0", 878 | "bundled": true, 879 | "dev": true, 880 | "optional": true, 881 | "requires": { 882 | "center-align": "0.1.3", 883 | "right-align": "0.1.3", 884 | "wordwrap": "0.0.2" 885 | }, 886 | "dependencies": { 887 | "wordwrap": { 888 | "version": "0.0.2", 889 | "bundled": true, 890 | "dev": true, 891 | "optional": true 892 | } 893 | } 894 | }, 895 | "code-point-at": { 896 | "version": "1.1.0", 897 | "bundled": true, 898 | "dev": true 899 | }, 900 | "commondir": { 901 | "version": "1.0.1", 902 | "bundled": true, 903 | "dev": true 904 | }, 905 | "concat-map": { 906 | "version": "0.0.1", 907 | "bundled": true, 908 | "dev": true 909 | }, 910 | "convert-source-map": { 911 | "version": "1.5.0", 912 | "bundled": true, 913 | "dev": true 914 | }, 915 | "core-js": { 916 | "version": "2.5.1", 917 | "bundled": true, 918 | "dev": true 919 | }, 920 | "cross-spawn": { 921 | "version": "4.0.2", 922 | "bundled": true, 923 | "dev": true, 924 | "requires": { 925 | "lru-cache": "4.1.1", 926 | "which": "1.3.0" 927 | } 928 | }, 929 | "debug": { 930 | "version": "2.6.9", 931 | "bundled": true, 932 | "dev": true, 933 | "requires": { 934 | "ms": "2.0.0" 935 | } 936 | }, 937 | "debug-log": { 938 | "version": "1.0.1", 939 | "bundled": true, 940 | "dev": true 941 | }, 942 | "decamelize": { 943 | "version": "1.2.0", 944 | "bundled": true, 945 | "dev": true 946 | }, 947 | "default-require-extensions": { 948 | "version": "1.0.0", 949 | "bundled": true, 950 | "dev": true, 951 | "requires": { 952 | "strip-bom": "2.0.0" 953 | } 954 | }, 955 | "detect-indent": { 956 | "version": "4.0.0", 957 | "bundled": true, 958 | "dev": true, 959 | "requires": { 960 | "repeating": "2.0.1" 961 | } 962 | }, 963 | "error-ex": { 964 | "version": "1.3.1", 965 | "bundled": true, 966 | "dev": true, 967 | "requires": { 968 | "is-arrayish": "0.2.1" 969 | } 970 | }, 971 | "escape-string-regexp": { 972 | "version": "1.0.5", 973 | "bundled": true, 974 | "dev": true 975 | }, 976 | "esutils": { 977 | "version": "2.0.2", 978 | "bundled": true, 979 | "dev": true 980 | }, 981 | "execa": { 982 | "version": "0.7.0", 983 | "bundled": true, 984 | "dev": true, 985 | "requires": { 986 | "cross-spawn": "5.1.0", 987 | "get-stream": "3.0.0", 988 | "is-stream": "1.1.0", 989 | "npm-run-path": "2.0.2", 990 | "p-finally": "1.0.0", 991 | "signal-exit": "3.0.2", 992 | "strip-eof": "1.0.0" 993 | }, 994 | "dependencies": { 995 | "cross-spawn": { 996 | "version": "5.1.0", 997 | "bundled": true, 998 | "dev": true, 999 | "requires": { 1000 | "lru-cache": "4.1.1", 1001 | "shebang-command": "1.2.0", 1002 | "which": "1.3.0" 1003 | } 1004 | } 1005 | } 1006 | }, 1007 | "expand-brackets": { 1008 | "version": "0.1.5", 1009 | "bundled": true, 1010 | "dev": true, 1011 | "requires": { 1012 | "is-posix-bracket": "0.1.1" 1013 | } 1014 | }, 1015 | "expand-range": { 1016 | "version": "1.8.2", 1017 | "bundled": true, 1018 | "dev": true, 1019 | "requires": { 1020 | "fill-range": "2.2.3" 1021 | } 1022 | }, 1023 | "extglob": { 1024 | "version": "0.3.2", 1025 | "bundled": true, 1026 | "dev": true, 1027 | "requires": { 1028 | "is-extglob": "1.0.0" 1029 | } 1030 | }, 1031 | "filename-regex": { 1032 | "version": "2.0.1", 1033 | "bundled": true, 1034 | "dev": true 1035 | }, 1036 | "fill-range": { 1037 | "version": "2.2.3", 1038 | "bundled": true, 1039 | "dev": true, 1040 | "requires": { 1041 | "is-number": "2.1.0", 1042 | "isobject": "2.1.0", 1043 | "randomatic": "1.1.7", 1044 | "repeat-element": "1.1.2", 1045 | "repeat-string": "1.6.1" 1046 | } 1047 | }, 1048 | "find-cache-dir": { 1049 | "version": "0.1.1", 1050 | "bundled": true, 1051 | "dev": true, 1052 | "requires": { 1053 | "commondir": "1.0.1", 1054 | "mkdirp": "0.5.1", 1055 | "pkg-dir": "1.0.0" 1056 | } 1057 | }, 1058 | "find-up": { 1059 | "version": "2.1.0", 1060 | "bundled": true, 1061 | "dev": true, 1062 | "requires": { 1063 | "locate-path": "2.0.0" 1064 | } 1065 | }, 1066 | "for-in": { 1067 | "version": "1.0.2", 1068 | "bundled": true, 1069 | "dev": true 1070 | }, 1071 | "for-own": { 1072 | "version": "0.1.5", 1073 | "bundled": true, 1074 | "dev": true, 1075 | "requires": { 1076 | "for-in": "1.0.2" 1077 | } 1078 | }, 1079 | "foreground-child": { 1080 | "version": "1.5.6", 1081 | "bundled": true, 1082 | "dev": true, 1083 | "requires": { 1084 | "cross-spawn": "4.0.2", 1085 | "signal-exit": "3.0.2" 1086 | } 1087 | }, 1088 | "fs.realpath": { 1089 | "version": "1.0.0", 1090 | "bundled": true, 1091 | "dev": true 1092 | }, 1093 | "get-caller-file": { 1094 | "version": "1.0.2", 1095 | "bundled": true, 1096 | "dev": true 1097 | }, 1098 | "get-stream": { 1099 | "version": "3.0.0", 1100 | "bundled": true, 1101 | "dev": true 1102 | }, 1103 | "glob": { 1104 | "version": "7.1.2", 1105 | "bundled": true, 1106 | "dev": true, 1107 | "requires": { 1108 | "fs.realpath": "1.0.0", 1109 | "inflight": "1.0.6", 1110 | "inherits": "2.0.3", 1111 | "minimatch": "3.0.4", 1112 | "once": "1.4.0", 1113 | "path-is-absolute": "1.0.1" 1114 | } 1115 | }, 1116 | "glob-base": { 1117 | "version": "0.3.0", 1118 | "bundled": true, 1119 | "dev": true, 1120 | "requires": { 1121 | "glob-parent": "2.0.0", 1122 | "is-glob": "2.0.1" 1123 | } 1124 | }, 1125 | "glob-parent": { 1126 | "version": "2.0.0", 1127 | "bundled": true, 1128 | "dev": true, 1129 | "requires": { 1130 | "is-glob": "2.0.1" 1131 | } 1132 | }, 1133 | "globals": { 1134 | "version": "9.18.0", 1135 | "bundled": true, 1136 | "dev": true 1137 | }, 1138 | "graceful-fs": { 1139 | "version": "4.1.11", 1140 | "bundled": true, 1141 | "dev": true 1142 | }, 1143 | "handlebars": { 1144 | "version": "4.0.11", 1145 | "bundled": true, 1146 | "dev": true, 1147 | "requires": { 1148 | "async": "1.5.2", 1149 | "optimist": "0.6.1", 1150 | "source-map": "0.4.4", 1151 | "uglify-js": "2.8.29" 1152 | }, 1153 | "dependencies": { 1154 | "source-map": { 1155 | "version": "0.4.4", 1156 | "bundled": true, 1157 | "dev": true, 1158 | "requires": { 1159 | "amdefine": "1.0.1" 1160 | } 1161 | } 1162 | } 1163 | }, 1164 | "has-ansi": { 1165 | "version": "2.0.0", 1166 | "bundled": true, 1167 | "dev": true, 1168 | "requires": { 1169 | "ansi-regex": "2.1.1" 1170 | } 1171 | }, 1172 | "has-flag": { 1173 | "version": "1.0.0", 1174 | "bundled": true, 1175 | "dev": true 1176 | }, 1177 | "hosted-git-info": { 1178 | "version": "2.5.0", 1179 | "bundled": true, 1180 | "dev": true 1181 | }, 1182 | "imurmurhash": { 1183 | "version": "0.1.4", 1184 | "bundled": true, 1185 | "dev": true 1186 | }, 1187 | "inflight": { 1188 | "version": "1.0.6", 1189 | "bundled": true, 1190 | "dev": true, 1191 | "requires": { 1192 | "once": "1.4.0", 1193 | "wrappy": "1.0.2" 1194 | } 1195 | }, 1196 | "inherits": { 1197 | "version": "2.0.3", 1198 | "bundled": true, 1199 | "dev": true 1200 | }, 1201 | "invariant": { 1202 | "version": "2.2.2", 1203 | "bundled": true, 1204 | "dev": true, 1205 | "requires": { 1206 | "loose-envify": "1.3.1" 1207 | } 1208 | }, 1209 | "invert-kv": { 1210 | "version": "1.0.0", 1211 | "bundled": true, 1212 | "dev": true 1213 | }, 1214 | "is-arrayish": { 1215 | "version": "0.2.1", 1216 | "bundled": true, 1217 | "dev": true 1218 | }, 1219 | "is-buffer": { 1220 | "version": "1.1.5", 1221 | "bundled": true, 1222 | "dev": true 1223 | }, 1224 | "is-builtin-module": { 1225 | "version": "1.0.0", 1226 | "bundled": true, 1227 | "dev": true, 1228 | "requires": { 1229 | "builtin-modules": "1.1.1" 1230 | } 1231 | }, 1232 | "is-dotfile": { 1233 | "version": "1.0.3", 1234 | "bundled": true, 1235 | "dev": true 1236 | }, 1237 | "is-equal-shallow": { 1238 | "version": "0.1.3", 1239 | "bundled": true, 1240 | "dev": true, 1241 | "requires": { 1242 | "is-primitive": "2.0.0" 1243 | } 1244 | }, 1245 | "is-extendable": { 1246 | "version": "0.1.1", 1247 | "bundled": true, 1248 | "dev": true 1249 | }, 1250 | "is-extglob": { 1251 | "version": "1.0.0", 1252 | "bundled": true, 1253 | "dev": true 1254 | }, 1255 | "is-finite": { 1256 | "version": "1.0.2", 1257 | "bundled": true, 1258 | "dev": true, 1259 | "requires": { 1260 | "number-is-nan": "1.0.1" 1261 | } 1262 | }, 1263 | "is-fullwidth-code-point": { 1264 | "version": "1.0.0", 1265 | "bundled": true, 1266 | "dev": true, 1267 | "requires": { 1268 | "number-is-nan": "1.0.1" 1269 | } 1270 | }, 1271 | "is-glob": { 1272 | "version": "2.0.1", 1273 | "bundled": true, 1274 | "dev": true, 1275 | "requires": { 1276 | "is-extglob": "1.0.0" 1277 | } 1278 | }, 1279 | "is-number": { 1280 | "version": "2.1.0", 1281 | "bundled": true, 1282 | "dev": true, 1283 | "requires": { 1284 | "kind-of": "3.2.2" 1285 | } 1286 | }, 1287 | "is-posix-bracket": { 1288 | "version": "0.1.1", 1289 | "bundled": true, 1290 | "dev": true 1291 | }, 1292 | "is-primitive": { 1293 | "version": "2.0.0", 1294 | "bundled": true, 1295 | "dev": true 1296 | }, 1297 | "is-stream": { 1298 | "version": "1.1.0", 1299 | "bundled": true, 1300 | "dev": true 1301 | }, 1302 | "is-utf8": { 1303 | "version": "0.2.1", 1304 | "bundled": true, 1305 | "dev": true 1306 | }, 1307 | "isarray": { 1308 | "version": "1.0.0", 1309 | "bundled": true, 1310 | "dev": true 1311 | }, 1312 | "isexe": { 1313 | "version": "2.0.0", 1314 | "bundled": true, 1315 | "dev": true 1316 | }, 1317 | "isobject": { 1318 | "version": "2.1.0", 1319 | "bundled": true, 1320 | "dev": true, 1321 | "requires": { 1322 | "isarray": "1.0.0" 1323 | } 1324 | }, 1325 | "istanbul-lib-coverage": { 1326 | "version": "1.1.1", 1327 | "bundled": true, 1328 | "dev": true 1329 | }, 1330 | "istanbul-lib-hook": { 1331 | "version": "1.1.0", 1332 | "bundled": true, 1333 | "dev": true, 1334 | "requires": { 1335 | "append-transform": "0.4.0" 1336 | } 1337 | }, 1338 | "istanbul-lib-instrument": { 1339 | "version": "1.9.1", 1340 | "bundled": true, 1341 | "dev": true, 1342 | "requires": { 1343 | "babel-generator": "6.26.0", 1344 | "babel-template": "6.26.0", 1345 | "babel-traverse": "6.26.0", 1346 | "babel-types": "6.26.0", 1347 | "babylon": "6.18.0", 1348 | "istanbul-lib-coverage": "1.1.1", 1349 | "semver": "5.4.1" 1350 | } 1351 | }, 1352 | "istanbul-lib-report": { 1353 | "version": "1.1.2", 1354 | "bundled": true, 1355 | "dev": true, 1356 | "requires": { 1357 | "istanbul-lib-coverage": "1.1.1", 1358 | "mkdirp": "0.5.1", 1359 | "path-parse": "1.0.5", 1360 | "supports-color": "3.2.3" 1361 | }, 1362 | "dependencies": { 1363 | "supports-color": { 1364 | "version": "3.2.3", 1365 | "bundled": true, 1366 | "dev": true, 1367 | "requires": { 1368 | "has-flag": "1.0.0" 1369 | } 1370 | } 1371 | } 1372 | }, 1373 | "istanbul-lib-source-maps": { 1374 | "version": "1.2.2", 1375 | "bundled": true, 1376 | "dev": true, 1377 | "requires": { 1378 | "debug": "3.1.0", 1379 | "istanbul-lib-coverage": "1.1.1", 1380 | "mkdirp": "0.5.1", 1381 | "rimraf": "2.6.2", 1382 | "source-map": "0.5.7" 1383 | }, 1384 | "dependencies": { 1385 | "debug": { 1386 | "version": "3.1.0", 1387 | "bundled": true, 1388 | "dev": true, 1389 | "requires": { 1390 | "ms": "2.0.0" 1391 | } 1392 | } 1393 | } 1394 | }, 1395 | "istanbul-reports": { 1396 | "version": "1.1.3", 1397 | "bundled": true, 1398 | "dev": true, 1399 | "requires": { 1400 | "handlebars": "4.0.11" 1401 | } 1402 | }, 1403 | "js-tokens": { 1404 | "version": "3.0.2", 1405 | "bundled": true, 1406 | "dev": true 1407 | }, 1408 | "jsesc": { 1409 | "version": "1.3.0", 1410 | "bundled": true, 1411 | "dev": true 1412 | }, 1413 | "kind-of": { 1414 | "version": "3.2.2", 1415 | "bundled": true, 1416 | "dev": true, 1417 | "requires": { 1418 | "is-buffer": "1.1.5" 1419 | } 1420 | }, 1421 | "lazy-cache": { 1422 | "version": "1.0.4", 1423 | "bundled": true, 1424 | "dev": true, 1425 | "optional": true 1426 | }, 1427 | "lcid": { 1428 | "version": "1.0.0", 1429 | "bundled": true, 1430 | "dev": true, 1431 | "requires": { 1432 | "invert-kv": "1.0.0" 1433 | } 1434 | }, 1435 | "load-json-file": { 1436 | "version": "1.1.0", 1437 | "bundled": true, 1438 | "dev": true, 1439 | "requires": { 1440 | "graceful-fs": "4.1.11", 1441 | "parse-json": "2.2.0", 1442 | "pify": "2.3.0", 1443 | "pinkie-promise": "2.0.1", 1444 | "strip-bom": "2.0.0" 1445 | } 1446 | }, 1447 | "locate-path": { 1448 | "version": "2.0.0", 1449 | "bundled": true, 1450 | "dev": true, 1451 | "requires": { 1452 | "p-locate": "2.0.0", 1453 | "path-exists": "3.0.0" 1454 | }, 1455 | "dependencies": { 1456 | "path-exists": { 1457 | "version": "3.0.0", 1458 | "bundled": true, 1459 | "dev": true 1460 | } 1461 | } 1462 | }, 1463 | "lodash": { 1464 | "version": "4.17.4", 1465 | "bundled": true, 1466 | "dev": true 1467 | }, 1468 | "longest": { 1469 | "version": "1.0.1", 1470 | "bundled": true, 1471 | "dev": true 1472 | }, 1473 | "loose-envify": { 1474 | "version": "1.3.1", 1475 | "bundled": true, 1476 | "dev": true, 1477 | "requires": { 1478 | "js-tokens": "3.0.2" 1479 | } 1480 | }, 1481 | "lru-cache": { 1482 | "version": "4.1.1", 1483 | "bundled": true, 1484 | "dev": true, 1485 | "requires": { 1486 | "pseudomap": "1.0.2", 1487 | "yallist": "2.1.2" 1488 | } 1489 | }, 1490 | "md5-hex": { 1491 | "version": "1.3.0", 1492 | "bundled": true, 1493 | "dev": true, 1494 | "requires": { 1495 | "md5-o-matic": "0.1.1" 1496 | } 1497 | }, 1498 | "md5-o-matic": { 1499 | "version": "0.1.1", 1500 | "bundled": true, 1501 | "dev": true 1502 | }, 1503 | "mem": { 1504 | "version": "1.1.0", 1505 | "bundled": true, 1506 | "dev": true, 1507 | "requires": { 1508 | "mimic-fn": "1.1.0" 1509 | } 1510 | }, 1511 | "merge-source-map": { 1512 | "version": "1.0.4", 1513 | "bundled": true, 1514 | "dev": true, 1515 | "requires": { 1516 | "source-map": "0.5.7" 1517 | } 1518 | }, 1519 | "micromatch": { 1520 | "version": "2.3.11", 1521 | "bundled": true, 1522 | "dev": true, 1523 | "requires": { 1524 | "arr-diff": "2.0.0", 1525 | "array-unique": "0.2.1", 1526 | "braces": "1.8.5", 1527 | "expand-brackets": "0.1.5", 1528 | "extglob": "0.3.2", 1529 | "filename-regex": "2.0.1", 1530 | "is-extglob": "1.0.0", 1531 | "is-glob": "2.0.1", 1532 | "kind-of": "3.2.2", 1533 | "normalize-path": "2.1.1", 1534 | "object.omit": "2.0.1", 1535 | "parse-glob": "3.0.4", 1536 | "regex-cache": "0.4.4" 1537 | } 1538 | }, 1539 | "mimic-fn": { 1540 | "version": "1.1.0", 1541 | "bundled": true, 1542 | "dev": true 1543 | }, 1544 | "minimatch": { 1545 | "version": "3.0.4", 1546 | "bundled": true, 1547 | "dev": true, 1548 | "requires": { 1549 | "brace-expansion": "1.1.8" 1550 | } 1551 | }, 1552 | "minimist": { 1553 | "version": "0.0.8", 1554 | "bundled": true, 1555 | "dev": true 1556 | }, 1557 | "mkdirp": { 1558 | "version": "0.5.1", 1559 | "bundled": true, 1560 | "dev": true, 1561 | "requires": { 1562 | "minimist": "0.0.8" 1563 | } 1564 | }, 1565 | "ms": { 1566 | "version": "2.0.0", 1567 | "bundled": true, 1568 | "dev": true 1569 | }, 1570 | "normalize-package-data": { 1571 | "version": "2.4.0", 1572 | "bundled": true, 1573 | "dev": true, 1574 | "requires": { 1575 | "hosted-git-info": "2.5.0", 1576 | "is-builtin-module": "1.0.0", 1577 | "semver": "5.4.1", 1578 | "validate-npm-package-license": "3.0.1" 1579 | } 1580 | }, 1581 | "normalize-path": { 1582 | "version": "2.1.1", 1583 | "bundled": true, 1584 | "dev": true, 1585 | "requires": { 1586 | "remove-trailing-separator": "1.1.0" 1587 | } 1588 | }, 1589 | "npm-run-path": { 1590 | "version": "2.0.2", 1591 | "bundled": true, 1592 | "dev": true, 1593 | "requires": { 1594 | "path-key": "2.0.1" 1595 | } 1596 | }, 1597 | "number-is-nan": { 1598 | "version": "1.0.1", 1599 | "bundled": true, 1600 | "dev": true 1601 | }, 1602 | "object-assign": { 1603 | "version": "4.1.1", 1604 | "bundled": true, 1605 | "dev": true 1606 | }, 1607 | "object.omit": { 1608 | "version": "2.0.1", 1609 | "bundled": true, 1610 | "dev": true, 1611 | "requires": { 1612 | "for-own": "0.1.5", 1613 | "is-extendable": "0.1.1" 1614 | } 1615 | }, 1616 | "once": { 1617 | "version": "1.4.0", 1618 | "bundled": true, 1619 | "dev": true, 1620 | "requires": { 1621 | "wrappy": "1.0.2" 1622 | } 1623 | }, 1624 | "optimist": { 1625 | "version": "0.6.1", 1626 | "bundled": true, 1627 | "dev": true, 1628 | "requires": { 1629 | "minimist": "0.0.8", 1630 | "wordwrap": "0.0.3" 1631 | } 1632 | }, 1633 | "os-homedir": { 1634 | "version": "1.0.2", 1635 | "bundled": true, 1636 | "dev": true 1637 | }, 1638 | "os-locale": { 1639 | "version": "2.1.0", 1640 | "bundled": true, 1641 | "dev": true, 1642 | "requires": { 1643 | "execa": "0.7.0", 1644 | "lcid": "1.0.0", 1645 | "mem": "1.1.0" 1646 | } 1647 | }, 1648 | "p-finally": { 1649 | "version": "1.0.0", 1650 | "bundled": true, 1651 | "dev": true 1652 | }, 1653 | "p-limit": { 1654 | "version": "1.1.0", 1655 | "bundled": true, 1656 | "dev": true 1657 | }, 1658 | "p-locate": { 1659 | "version": "2.0.0", 1660 | "bundled": true, 1661 | "dev": true, 1662 | "requires": { 1663 | "p-limit": "1.1.0" 1664 | } 1665 | }, 1666 | "parse-glob": { 1667 | "version": "3.0.4", 1668 | "bundled": true, 1669 | "dev": true, 1670 | "requires": { 1671 | "glob-base": "0.3.0", 1672 | "is-dotfile": "1.0.3", 1673 | "is-extglob": "1.0.0", 1674 | "is-glob": "2.0.1" 1675 | } 1676 | }, 1677 | "parse-json": { 1678 | "version": "2.2.0", 1679 | "bundled": true, 1680 | "dev": true, 1681 | "requires": { 1682 | "error-ex": "1.3.1" 1683 | } 1684 | }, 1685 | "path-exists": { 1686 | "version": "2.1.0", 1687 | "bundled": true, 1688 | "dev": true, 1689 | "requires": { 1690 | "pinkie-promise": "2.0.1" 1691 | } 1692 | }, 1693 | "path-is-absolute": { 1694 | "version": "1.0.1", 1695 | "bundled": true, 1696 | "dev": true 1697 | }, 1698 | "path-key": { 1699 | "version": "2.0.1", 1700 | "bundled": true, 1701 | "dev": true 1702 | }, 1703 | "path-parse": { 1704 | "version": "1.0.5", 1705 | "bundled": true, 1706 | "dev": true 1707 | }, 1708 | "path-type": { 1709 | "version": "1.1.0", 1710 | "bundled": true, 1711 | "dev": true, 1712 | "requires": { 1713 | "graceful-fs": "4.1.11", 1714 | "pify": "2.3.0", 1715 | "pinkie-promise": "2.0.1" 1716 | } 1717 | }, 1718 | "pify": { 1719 | "version": "2.3.0", 1720 | "bundled": true, 1721 | "dev": true 1722 | }, 1723 | "pinkie": { 1724 | "version": "2.0.4", 1725 | "bundled": true, 1726 | "dev": true 1727 | }, 1728 | "pinkie-promise": { 1729 | "version": "2.0.1", 1730 | "bundled": true, 1731 | "dev": true, 1732 | "requires": { 1733 | "pinkie": "2.0.4" 1734 | } 1735 | }, 1736 | "pkg-dir": { 1737 | "version": "1.0.0", 1738 | "bundled": true, 1739 | "dev": true, 1740 | "requires": { 1741 | "find-up": "1.1.2" 1742 | }, 1743 | "dependencies": { 1744 | "find-up": { 1745 | "version": "1.1.2", 1746 | "bundled": true, 1747 | "dev": true, 1748 | "requires": { 1749 | "path-exists": "2.1.0", 1750 | "pinkie-promise": "2.0.1" 1751 | } 1752 | } 1753 | } 1754 | }, 1755 | "preserve": { 1756 | "version": "0.2.0", 1757 | "bundled": true, 1758 | "dev": true 1759 | }, 1760 | "pseudomap": { 1761 | "version": "1.0.2", 1762 | "bundled": true, 1763 | "dev": true 1764 | }, 1765 | "randomatic": { 1766 | "version": "1.1.7", 1767 | "bundled": true, 1768 | "dev": true, 1769 | "requires": { 1770 | "is-number": "3.0.0", 1771 | "kind-of": "4.0.0" 1772 | }, 1773 | "dependencies": { 1774 | "is-number": { 1775 | "version": "3.0.0", 1776 | "bundled": true, 1777 | "dev": true, 1778 | "requires": { 1779 | "kind-of": "3.2.2" 1780 | }, 1781 | "dependencies": { 1782 | "kind-of": { 1783 | "version": "3.2.2", 1784 | "bundled": true, 1785 | "dev": true, 1786 | "requires": { 1787 | "is-buffer": "1.1.5" 1788 | } 1789 | } 1790 | } 1791 | }, 1792 | "kind-of": { 1793 | "version": "4.0.0", 1794 | "bundled": true, 1795 | "dev": true, 1796 | "requires": { 1797 | "is-buffer": "1.1.5" 1798 | } 1799 | } 1800 | } 1801 | }, 1802 | "read-pkg": { 1803 | "version": "1.1.0", 1804 | "bundled": true, 1805 | "dev": true, 1806 | "requires": { 1807 | "load-json-file": "1.1.0", 1808 | "normalize-package-data": "2.4.0", 1809 | "path-type": "1.1.0" 1810 | } 1811 | }, 1812 | "read-pkg-up": { 1813 | "version": "1.0.1", 1814 | "bundled": true, 1815 | "dev": true, 1816 | "requires": { 1817 | "find-up": "1.1.2", 1818 | "read-pkg": "1.1.0" 1819 | }, 1820 | "dependencies": { 1821 | "find-up": { 1822 | "version": "1.1.2", 1823 | "bundled": true, 1824 | "dev": true, 1825 | "requires": { 1826 | "path-exists": "2.1.0", 1827 | "pinkie-promise": "2.0.1" 1828 | } 1829 | } 1830 | } 1831 | }, 1832 | "regenerator-runtime": { 1833 | "version": "0.11.0", 1834 | "bundled": true, 1835 | "dev": true 1836 | }, 1837 | "regex-cache": { 1838 | "version": "0.4.4", 1839 | "bundled": true, 1840 | "dev": true, 1841 | "requires": { 1842 | "is-equal-shallow": "0.1.3" 1843 | } 1844 | }, 1845 | "remove-trailing-separator": { 1846 | "version": "1.1.0", 1847 | "bundled": true, 1848 | "dev": true 1849 | }, 1850 | "repeat-element": { 1851 | "version": "1.1.2", 1852 | "bundled": true, 1853 | "dev": true 1854 | }, 1855 | "repeat-string": { 1856 | "version": "1.6.1", 1857 | "bundled": true, 1858 | "dev": true 1859 | }, 1860 | "repeating": { 1861 | "version": "2.0.1", 1862 | "bundled": true, 1863 | "dev": true, 1864 | "requires": { 1865 | "is-finite": "1.0.2" 1866 | } 1867 | }, 1868 | "require-directory": { 1869 | "version": "2.1.1", 1870 | "bundled": true, 1871 | "dev": true 1872 | }, 1873 | "require-main-filename": { 1874 | "version": "1.0.1", 1875 | "bundled": true, 1876 | "dev": true 1877 | }, 1878 | "resolve-from": { 1879 | "version": "2.0.0", 1880 | "bundled": true, 1881 | "dev": true 1882 | }, 1883 | "right-align": { 1884 | "version": "0.1.3", 1885 | "bundled": true, 1886 | "dev": true, 1887 | "optional": true, 1888 | "requires": { 1889 | "align-text": "0.1.4" 1890 | } 1891 | }, 1892 | "rimraf": { 1893 | "version": "2.6.2", 1894 | "bundled": true, 1895 | "dev": true, 1896 | "requires": { 1897 | "glob": "7.1.2" 1898 | } 1899 | }, 1900 | "semver": { 1901 | "version": "5.4.1", 1902 | "bundled": true, 1903 | "dev": true 1904 | }, 1905 | "set-blocking": { 1906 | "version": "2.0.0", 1907 | "bundled": true, 1908 | "dev": true 1909 | }, 1910 | "shebang-command": { 1911 | "version": "1.2.0", 1912 | "bundled": true, 1913 | "dev": true, 1914 | "requires": { 1915 | "shebang-regex": "1.0.0" 1916 | } 1917 | }, 1918 | "shebang-regex": { 1919 | "version": "1.0.0", 1920 | "bundled": true, 1921 | "dev": true 1922 | }, 1923 | "signal-exit": { 1924 | "version": "3.0.2", 1925 | "bundled": true, 1926 | "dev": true 1927 | }, 1928 | "slide": { 1929 | "version": "1.1.6", 1930 | "bundled": true, 1931 | "dev": true 1932 | }, 1933 | "source-map": { 1934 | "version": "0.5.7", 1935 | "bundled": true, 1936 | "dev": true 1937 | }, 1938 | "spawn-wrap": { 1939 | "version": "1.3.8", 1940 | "bundled": true, 1941 | "dev": true, 1942 | "requires": { 1943 | "foreground-child": "1.5.6", 1944 | "mkdirp": "0.5.1", 1945 | "os-homedir": "1.0.2", 1946 | "rimraf": "2.6.2", 1947 | "signal-exit": "3.0.2", 1948 | "which": "1.3.0" 1949 | } 1950 | }, 1951 | "spdx-correct": { 1952 | "version": "1.0.2", 1953 | "bundled": true, 1954 | "dev": true, 1955 | "requires": { 1956 | "spdx-license-ids": "1.2.2" 1957 | } 1958 | }, 1959 | "spdx-expression-parse": { 1960 | "version": "1.0.4", 1961 | "bundled": true, 1962 | "dev": true 1963 | }, 1964 | "spdx-license-ids": { 1965 | "version": "1.2.2", 1966 | "bundled": true, 1967 | "dev": true 1968 | }, 1969 | "string-width": { 1970 | "version": "2.1.1", 1971 | "bundled": true, 1972 | "dev": true, 1973 | "requires": { 1974 | "is-fullwidth-code-point": "2.0.0", 1975 | "strip-ansi": "4.0.0" 1976 | }, 1977 | "dependencies": { 1978 | "ansi-regex": { 1979 | "version": "3.0.0", 1980 | "bundled": true, 1981 | "dev": true 1982 | }, 1983 | "is-fullwidth-code-point": { 1984 | "version": "2.0.0", 1985 | "bundled": true, 1986 | "dev": true 1987 | }, 1988 | "strip-ansi": { 1989 | "version": "4.0.0", 1990 | "bundled": true, 1991 | "dev": true, 1992 | "requires": { 1993 | "ansi-regex": "3.0.0" 1994 | } 1995 | } 1996 | } 1997 | }, 1998 | "strip-ansi": { 1999 | "version": "3.0.1", 2000 | "bundled": true, 2001 | "dev": true, 2002 | "requires": { 2003 | "ansi-regex": "2.1.1" 2004 | } 2005 | }, 2006 | "strip-bom": { 2007 | "version": "2.0.0", 2008 | "bundled": true, 2009 | "dev": true, 2010 | "requires": { 2011 | "is-utf8": "0.2.1" 2012 | } 2013 | }, 2014 | "strip-eof": { 2015 | "version": "1.0.0", 2016 | "bundled": true, 2017 | "dev": true 2018 | }, 2019 | "supports-color": { 2020 | "version": "2.0.0", 2021 | "bundled": true, 2022 | "dev": true 2023 | }, 2024 | "test-exclude": { 2025 | "version": "4.1.1", 2026 | "bundled": true, 2027 | "dev": true, 2028 | "requires": { 2029 | "arrify": "1.0.1", 2030 | "micromatch": "2.3.11", 2031 | "object-assign": "4.1.1", 2032 | "read-pkg-up": "1.0.1", 2033 | "require-main-filename": "1.0.1" 2034 | } 2035 | }, 2036 | "to-fast-properties": { 2037 | "version": "1.0.3", 2038 | "bundled": true, 2039 | "dev": true 2040 | }, 2041 | "trim-right": { 2042 | "version": "1.0.1", 2043 | "bundled": true, 2044 | "dev": true 2045 | }, 2046 | "uglify-js": { 2047 | "version": "2.8.29", 2048 | "bundled": true, 2049 | "dev": true, 2050 | "optional": true, 2051 | "requires": { 2052 | "source-map": "0.5.7", 2053 | "uglify-to-browserify": "1.0.2", 2054 | "yargs": "3.10.0" 2055 | }, 2056 | "dependencies": { 2057 | "yargs": { 2058 | "version": "3.10.0", 2059 | "bundled": true, 2060 | "dev": true, 2061 | "optional": true, 2062 | "requires": { 2063 | "camelcase": "1.2.1", 2064 | "cliui": "2.1.0", 2065 | "decamelize": "1.2.0", 2066 | "window-size": "0.1.0" 2067 | } 2068 | } 2069 | } 2070 | }, 2071 | "uglify-to-browserify": { 2072 | "version": "1.0.2", 2073 | "bundled": true, 2074 | "dev": true, 2075 | "optional": true 2076 | }, 2077 | "validate-npm-package-license": { 2078 | "version": "3.0.1", 2079 | "bundled": true, 2080 | "dev": true, 2081 | "requires": { 2082 | "spdx-correct": "1.0.2", 2083 | "spdx-expression-parse": "1.0.4" 2084 | } 2085 | }, 2086 | "which": { 2087 | "version": "1.3.0", 2088 | "bundled": true, 2089 | "dev": true, 2090 | "requires": { 2091 | "isexe": "2.0.0" 2092 | } 2093 | }, 2094 | "which-module": { 2095 | "version": "2.0.0", 2096 | "bundled": true, 2097 | "dev": true 2098 | }, 2099 | "window-size": { 2100 | "version": "0.1.0", 2101 | "bundled": true, 2102 | "dev": true, 2103 | "optional": true 2104 | }, 2105 | "wordwrap": { 2106 | "version": "0.0.3", 2107 | "bundled": true, 2108 | "dev": true 2109 | }, 2110 | "wrap-ansi": { 2111 | "version": "2.1.0", 2112 | "bundled": true, 2113 | "dev": true, 2114 | "requires": { 2115 | "string-width": "1.0.2", 2116 | "strip-ansi": "3.0.1" 2117 | }, 2118 | "dependencies": { 2119 | "string-width": { 2120 | "version": "1.0.2", 2121 | "bundled": true, 2122 | "dev": true, 2123 | "requires": { 2124 | "code-point-at": "1.1.0", 2125 | "is-fullwidth-code-point": "1.0.0", 2126 | "strip-ansi": "3.0.1" 2127 | } 2128 | } 2129 | } 2130 | }, 2131 | "wrappy": { 2132 | "version": "1.0.2", 2133 | "bundled": true, 2134 | "dev": true 2135 | }, 2136 | "write-file-atomic": { 2137 | "version": "1.3.4", 2138 | "bundled": true, 2139 | "dev": true, 2140 | "requires": { 2141 | "graceful-fs": "4.1.11", 2142 | "imurmurhash": "0.1.4", 2143 | "slide": "1.1.6" 2144 | } 2145 | }, 2146 | "y18n": { 2147 | "version": "3.2.1", 2148 | "bundled": true, 2149 | "dev": true 2150 | }, 2151 | "yallist": { 2152 | "version": "2.1.2", 2153 | "bundled": true, 2154 | "dev": true 2155 | }, 2156 | "yargs": { 2157 | "version": "10.0.3", 2158 | "bundled": true, 2159 | "dev": true, 2160 | "requires": { 2161 | "cliui": "3.2.0", 2162 | "decamelize": "1.2.0", 2163 | "find-up": "2.1.0", 2164 | "get-caller-file": "1.0.2", 2165 | "os-locale": "2.1.0", 2166 | "require-directory": "2.1.1", 2167 | "require-main-filename": "1.0.1", 2168 | "set-blocking": "2.0.0", 2169 | "string-width": "2.1.1", 2170 | "which-module": "2.0.0", 2171 | "y18n": "3.2.1", 2172 | "yargs-parser": "8.0.0" 2173 | }, 2174 | "dependencies": { 2175 | "cliui": { 2176 | "version": "3.2.0", 2177 | "bundled": true, 2178 | "dev": true, 2179 | "requires": { 2180 | "string-width": "1.0.2", 2181 | "strip-ansi": "3.0.1", 2182 | "wrap-ansi": "2.1.0" 2183 | }, 2184 | "dependencies": { 2185 | "string-width": { 2186 | "version": "1.0.2", 2187 | "bundled": true, 2188 | "dev": true, 2189 | "requires": { 2190 | "code-point-at": "1.1.0", 2191 | "is-fullwidth-code-point": "1.0.0", 2192 | "strip-ansi": "3.0.1" 2193 | } 2194 | } 2195 | } 2196 | } 2197 | } 2198 | }, 2199 | "yargs-parser": { 2200 | "version": "8.0.0", 2201 | "bundled": true, 2202 | "dev": true, 2203 | "requires": { 2204 | "camelcase": "4.1.0" 2205 | }, 2206 | "dependencies": { 2207 | "camelcase": { 2208 | "version": "4.1.0", 2209 | "bundled": true, 2210 | "dev": true 2211 | } 2212 | } 2213 | } 2214 | } 2215 | }, 2216 | "oauth-sign": { 2217 | "version": "0.8.2", 2218 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", 2219 | "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", 2220 | "dev": true 2221 | }, 2222 | "once": { 2223 | "version": "1.4.0", 2224 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 2225 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 2226 | "dev": true, 2227 | "requires": { 2228 | "wrappy": "1.0.2" 2229 | } 2230 | }, 2231 | "opener": { 2232 | "version": "1.4.3", 2233 | "resolved": "https://registry.npmjs.org/opener/-/opener-1.4.3.tgz", 2234 | "integrity": "sha1-XG2ixdflgx6P+jlklQ+NZnSskLg=", 2235 | "dev": true 2236 | }, 2237 | "os-homedir": { 2238 | "version": "1.0.2", 2239 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 2240 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 2241 | "dev": true 2242 | }, 2243 | "own-or": { 2244 | "version": "1.0.0", 2245 | "resolved": "https://registry.npmjs.org/own-or/-/own-or-1.0.0.tgz", 2246 | "integrity": "sha1-Tod/vtqaLsgAD7wLyuOWRe6L+Nw=", 2247 | "dev": true 2248 | }, 2249 | "own-or-env": { 2250 | "version": "1.0.0", 2251 | "resolved": "https://registry.npmjs.org/own-or-env/-/own-or-env-1.0.0.tgz", 2252 | "integrity": "sha1-nvkg/IHi5jz1nUEQElg2jPT8pPs=", 2253 | "dev": true 2254 | }, 2255 | "path-is-absolute": { 2256 | "version": "1.0.1", 2257 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 2258 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 2259 | "dev": true 2260 | }, 2261 | "pinkie": { 2262 | "version": "2.0.4", 2263 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 2264 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 2265 | "dev": true 2266 | }, 2267 | "pinkie-promise": { 2268 | "version": "2.0.1", 2269 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 2270 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 2271 | "dev": true, 2272 | "requires": { 2273 | "pinkie": "2.0.4" 2274 | } 2275 | }, 2276 | "process-nextick-args": { 2277 | "version": "1.0.7", 2278 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", 2279 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", 2280 | "dev": true 2281 | }, 2282 | "pseudomap": { 2283 | "version": "1.0.2", 2284 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", 2285 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", 2286 | "dev": true 2287 | }, 2288 | "punycode": { 2289 | "version": "1.4.1", 2290 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 2291 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", 2292 | "dev": true 2293 | }, 2294 | "qs": { 2295 | "version": "6.3.2", 2296 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", 2297 | "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", 2298 | "dev": true 2299 | }, 2300 | "readable-stream": { 2301 | "version": "2.3.3", 2302 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", 2303 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", 2304 | "dev": true, 2305 | "requires": { 2306 | "core-util-is": "1.0.2", 2307 | "inherits": "2.0.3", 2308 | "isarray": "1.0.0", 2309 | "process-nextick-args": "1.0.7", 2310 | "safe-buffer": "5.1.1", 2311 | "string_decoder": "1.0.3", 2312 | "util-deprecate": "1.0.2" 2313 | } 2314 | }, 2315 | "request": { 2316 | "version": "2.79.0", 2317 | "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", 2318 | "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", 2319 | "dev": true, 2320 | "requires": { 2321 | "aws-sign2": "0.6.0", 2322 | "aws4": "1.6.0", 2323 | "caseless": "0.11.0", 2324 | "combined-stream": "1.0.5", 2325 | "extend": "3.0.1", 2326 | "forever-agent": "0.6.1", 2327 | "form-data": "2.1.4", 2328 | "har-validator": "2.0.6", 2329 | "hawk": "3.1.3", 2330 | "http-signature": "1.1.1", 2331 | "is-typedarray": "1.0.0", 2332 | "isstream": "0.1.2", 2333 | "json-stringify-safe": "5.0.1", 2334 | "mime-types": "2.1.17", 2335 | "oauth-sign": "0.8.2", 2336 | "qs": "6.3.2", 2337 | "stringstream": "0.0.5", 2338 | "tough-cookie": "2.3.3", 2339 | "tunnel-agent": "0.4.3", 2340 | "uuid": "3.1.0" 2341 | } 2342 | }, 2343 | "safe-buffer": { 2344 | "version": "5.1.1", 2345 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 2346 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", 2347 | "dev": true 2348 | }, 2349 | "semver": { 2350 | "version": "5.4.1", 2351 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", 2352 | "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" 2353 | }, 2354 | "shimmer": { 2355 | "version": "1.2.0", 2356 | "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.0.tgz", 2357 | "integrity": "sha512-xTCx2vohXC2EWWDqY/zb4+5Mu28D+HYNSOuFzsyRDRvI/e1ICb69afwaUwfjr+25ZXldbOLyp+iDUZHq8UnTag==" 2358 | }, 2359 | "signal-exit": { 2360 | "version": "3.0.2", 2361 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 2362 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 2363 | "dev": true 2364 | }, 2365 | "sntp": { 2366 | "version": "1.0.9", 2367 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", 2368 | "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", 2369 | "dev": true, 2370 | "requires": { 2371 | "hoek": "2.16.3" 2372 | } 2373 | }, 2374 | "source-map": { 2375 | "version": "0.5.7", 2376 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 2377 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 2378 | "dev": true 2379 | }, 2380 | "source-map-support": { 2381 | "version": "0.4.18", 2382 | "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", 2383 | "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", 2384 | "dev": true, 2385 | "requires": { 2386 | "source-map": "0.5.7" 2387 | } 2388 | }, 2389 | "sprintf-js": { 2390 | "version": "1.0.3", 2391 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 2392 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 2393 | "dev": true 2394 | }, 2395 | "sshpk": { 2396 | "version": "1.13.1", 2397 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", 2398 | "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", 2399 | "dev": true, 2400 | "requires": { 2401 | "asn1": "0.2.3", 2402 | "assert-plus": "1.0.0", 2403 | "bcrypt-pbkdf": "1.0.1", 2404 | "dashdash": "1.14.1", 2405 | "ecc-jsbn": "0.1.1", 2406 | "getpass": "0.1.7", 2407 | "jsbn": "0.1.1", 2408 | "tweetnacl": "0.14.5" 2409 | }, 2410 | "dependencies": { 2411 | "assert-plus": { 2412 | "version": "1.0.0", 2413 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 2414 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 2415 | "dev": true 2416 | } 2417 | } 2418 | }, 2419 | "stack-utils": { 2420 | "version": "1.0.1", 2421 | "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.1.tgz", 2422 | "integrity": "sha1-1PM6tU6OOHeLDKXP07OvsS22hiA=", 2423 | "dev": true 2424 | }, 2425 | "string_decoder": { 2426 | "version": "1.0.3", 2427 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", 2428 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", 2429 | "dev": true, 2430 | "requires": { 2431 | "safe-buffer": "5.1.1" 2432 | } 2433 | }, 2434 | "stringstream": { 2435 | "version": "0.0.5", 2436 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", 2437 | "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", 2438 | "dev": true 2439 | }, 2440 | "strip-ansi": { 2441 | "version": "3.0.1", 2442 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 2443 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 2444 | "dev": true, 2445 | "requires": { 2446 | "ansi-regex": "2.1.1" 2447 | } 2448 | }, 2449 | "supports-color": { 2450 | "version": "2.0.0", 2451 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", 2452 | "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", 2453 | "dev": true 2454 | }, 2455 | "tap": { 2456 | "version": "10.7.3", 2457 | "resolved": "https://registry.npmjs.org/tap/-/tap-10.7.3.tgz", 2458 | "integrity": "sha1-9cIMByFRqLaHfngRJxSgcAe5fk8=", 2459 | "dev": true, 2460 | "requires": { 2461 | "bind-obj-methods": "1.0.0", 2462 | "bluebird": "3.5.1", 2463 | "clean-yaml-object": "0.1.0", 2464 | "color-support": "1.1.3", 2465 | "coveralls": "2.13.3", 2466 | "foreground-child": "1.5.6", 2467 | "fs-exists-cached": "1.0.0", 2468 | "function-loop": "1.0.1", 2469 | "glob": "7.1.2", 2470 | "isexe": "2.0.0", 2471 | "js-yaml": "3.10.0", 2472 | "nyc": "11.3.0", 2473 | "opener": "1.4.3", 2474 | "os-homedir": "1.0.2", 2475 | "own-or": "1.0.0", 2476 | "own-or-env": "1.0.0", 2477 | "readable-stream": "2.3.3", 2478 | "signal-exit": "3.0.2", 2479 | "source-map-support": "0.4.18", 2480 | "stack-utils": "1.0.1", 2481 | "tap-mocha-reporter": "3.0.6", 2482 | "tap-parser": "5.4.0", 2483 | "tmatch": "3.1.0", 2484 | "trivial-deferred": "1.0.1", 2485 | "tsame": "1.1.2", 2486 | "yapool": "1.0.0" 2487 | } 2488 | }, 2489 | "tap-mocha-reporter": { 2490 | "version": "3.0.6", 2491 | "resolved": "https://registry.npmjs.org/tap-mocha-reporter/-/tap-mocha-reporter-3.0.6.tgz", 2492 | "integrity": "sha512-UImgw3etckDQCoqZIAIKcQDt0w1JLVs3v0yxLlmwvGLZl6MGFxF7JME5PElXjAoDklVDU42P3vVu5jgr37P4Yg==", 2493 | "dev": true, 2494 | "requires": { 2495 | "color-support": "1.1.3", 2496 | "debug": "2.6.9", 2497 | "diff": "1.4.0", 2498 | "escape-string-regexp": "1.0.5", 2499 | "glob": "7.1.2", 2500 | "js-yaml": "3.10.0", 2501 | "readable-stream": "2.3.3", 2502 | "tap-parser": "5.4.0", 2503 | "unicode-length": "1.0.3" 2504 | } 2505 | }, 2506 | "tap-parser": { 2507 | "version": "5.4.0", 2508 | "resolved": "https://registry.npmjs.org/tap-parser/-/tap-parser-5.4.0.tgz", 2509 | "integrity": "sha512-BIsIaGqv7uTQgTW1KLTMNPSEQf4zDDPgYOBRdgOfuB+JFOLRBfEu6cLa/KvMvmqggu1FKXDfitjLwsq4827RvA==", 2510 | "dev": true, 2511 | "requires": { 2512 | "events-to-array": "1.1.2", 2513 | "js-yaml": "3.10.0", 2514 | "readable-stream": "2.3.3" 2515 | } 2516 | }, 2517 | "tmatch": { 2518 | "version": "3.1.0", 2519 | "resolved": "https://registry.npmjs.org/tmatch/-/tmatch-3.1.0.tgz", 2520 | "integrity": "sha512-W3MSATOCN4pVu2qFxmJLIArSifeSOFqnfx9hiUaVgOmeRoI2NbU7RNga+6G+L8ojlFeQge+ZPCclWyUpQ8UeNQ==", 2521 | "dev": true 2522 | }, 2523 | "tough-cookie": { 2524 | "version": "2.3.3", 2525 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", 2526 | "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", 2527 | "dev": true, 2528 | "requires": { 2529 | "punycode": "1.4.1" 2530 | } 2531 | }, 2532 | "trivial-deferred": { 2533 | "version": "1.0.1", 2534 | "resolved": "https://registry.npmjs.org/trivial-deferred/-/trivial-deferred-1.0.1.tgz", 2535 | "integrity": "sha1-N21NKdlR1jaKb3oK6FwvTV4GWPM=", 2536 | "dev": true 2537 | }, 2538 | "tsame": { 2539 | "version": "1.1.2", 2540 | "resolved": "https://registry.npmjs.org/tsame/-/tsame-1.1.2.tgz", 2541 | "integrity": "sha512-ovCs24PGjmByVPr9tSIOs/yjUX9sJl0grEmOsj9dZA/UknQkgPOKcUqM84aSCvt9awHuhc/boMzTg3BHFalxWw==", 2542 | "dev": true 2543 | }, 2544 | "tunnel-agent": { 2545 | "version": "0.4.3", 2546 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", 2547 | "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", 2548 | "dev": true 2549 | }, 2550 | "tweetnacl": { 2551 | "version": "0.14.5", 2552 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 2553 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", 2554 | "dev": true, 2555 | "optional": true 2556 | }, 2557 | "unicode-length": { 2558 | "version": "1.0.3", 2559 | "resolved": "https://registry.npmjs.org/unicode-length/-/unicode-length-1.0.3.tgz", 2560 | "integrity": "sha1-Wtp6f+1RhBpBijKM8UlHisg1irs=", 2561 | "dev": true, 2562 | "requires": { 2563 | "punycode": "1.4.1", 2564 | "strip-ansi": "3.0.1" 2565 | } 2566 | }, 2567 | "util-deprecate": { 2568 | "version": "1.0.2", 2569 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2570 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 2571 | "dev": true 2572 | }, 2573 | "uuid": { 2574 | "version": "3.1.0", 2575 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", 2576 | "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", 2577 | "dev": true 2578 | }, 2579 | "verror": { 2580 | "version": "1.10.0", 2581 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 2582 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 2583 | "dev": true, 2584 | "requires": { 2585 | "assert-plus": "1.0.0", 2586 | "core-util-is": "1.0.2", 2587 | "extsprintf": "1.3.0" 2588 | }, 2589 | "dependencies": { 2590 | "assert-plus": { 2591 | "version": "1.0.0", 2592 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 2593 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", 2594 | "dev": true 2595 | } 2596 | } 2597 | }, 2598 | "which": { 2599 | "version": "1.3.0", 2600 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", 2601 | "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", 2602 | "dev": true, 2603 | "requires": { 2604 | "isexe": "2.0.0" 2605 | } 2606 | }, 2607 | "wrappy": { 2608 | "version": "1.0.2", 2609 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2610 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 2611 | "dev": true 2612 | }, 2613 | "xtend": { 2614 | "version": "4.0.1", 2615 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", 2616 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", 2617 | "dev": true 2618 | }, 2619 | "yallist": { 2620 | "version": "2.1.2", 2621 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", 2622 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", 2623 | "dev": true 2624 | }, 2625 | "yapool": { 2626 | "version": "1.0.0", 2627 | "resolved": "https://registry.npmjs.org/yapool/-/yapool-1.0.0.tgz", 2628 | "integrity": "sha1-9pPymjFbUNmp2iZGp6ZkXJaYW2o=", 2629 | "dev": true 2630 | } 2631 | } 2632 | } 2633 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "continuation-local-storage", 3 | "version": "3.2.1", 4 | "description": "userland implementation of https://github.com/joyent/node/issues/5243", 5 | "main": "context.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "tap test/*.tap.js" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/othiym23/node-continuation-local-storage.git" 15 | }, 16 | "keywords": [ 17 | "threading", 18 | "shared", 19 | "context", 20 | "domains", 21 | "tracing", 22 | "logging" 23 | ], 24 | "author": "Forrest L Norvell ", 25 | "contributors": [ 26 | "Tim Caswell ", 27 | "Forrest L Norvell " 28 | ], 29 | "license": "BSD-2-Clause", 30 | "devDependencies": { 31 | "semver": "^5.4.1", 32 | "tap": "^10.3.1" 33 | }, 34 | "dependencies": { 35 | "async-listener": "^0.6.0", 36 | "emitter-listener": "^1.1.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/async-context.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var tap = require('tap') 4 | , test = tap.test 5 | , createNamespace = require('../context.js').createNamespace 6 | ; 7 | 8 | test("asynchronously propagating state with local-context-domains", function (t) { 9 | t.plan(2); 10 | 11 | var namespace = createNamespace('namespace'); 12 | t.ok(process.namespaces.namespace, "namespace has been created"); 13 | 14 | namespace.run(function () { 15 | namespace.set('test', 1337); 16 | t.equal(namespace.get('test'), 1337, "namespace is working"); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/async-no-run-queue-multiple.tap.js: -------------------------------------------------------------------------------- 1 | var test = require('tap').test 2 | , cls = require('../context.js') 3 | ; 4 | 5 | test("minimized test case that caused #6011 patch to fail", function (t) { 6 | t.plan(3); 7 | 8 | console.log('+'); 9 | // when the flaw was in the patch, commenting out this line would fix things: 10 | process.nextTick(function () { console.log('!'); }); 11 | 12 | var n = cls.createNamespace("test"); 13 | t.ok(!n.get('state'), "state should not yet be visible"); 14 | 15 | n.run(function () { 16 | n.set('state', true); 17 | t.ok(n.get('state'), "state should be visible"); 18 | 19 | process.nextTick(function () { 20 | t.ok(n.get('state'), "state should be visible"); 21 | }); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/bind-emitter.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tap').test 4 | , EventEmitter = require('events').EventEmitter 5 | , cls = require('../context.js') 6 | ; 7 | 8 | test("event emitters bound to CLS context", function (t) { 9 | t.plan(13); 10 | 11 | t.test("handler registered in context, emit out of context", function (t) { 12 | t.plan(1); 13 | 14 | var n = cls.createNamespace('in') 15 | , ee = new EventEmitter() 16 | ; 17 | 18 | n.run(function () { 19 | n.set('value', 'hello'); 20 | n.bindEmitter(ee); 21 | ee.on('event', function () { 22 | t.equal(n.get('value'), 'hello', "value still set in EE."); 23 | cls.destroyNamespace('in'); 24 | }); 25 | }); 26 | 27 | ee.emit('event'); 28 | }); 29 | 30 | t.test("once handler registered in context", function (t) { 31 | t.plan(1); 32 | 33 | var n = cls.createNamespace('inOnce') 34 | , ee = new EventEmitter() 35 | ; 36 | 37 | n.run(function () { 38 | n.set('value', 'hello'); 39 | n.bindEmitter(ee); 40 | ee.once('event', function () { 41 | t.equal(n.get('value'), 'hello', "value still set in EE."); 42 | cls.destroyNamespace('inOnce'); 43 | }); 44 | }); 45 | 46 | ee.emit('event'); 47 | }); 48 | 49 | t.test("handler registered out of context, emit in context", function (t) { 50 | t.plan(1); 51 | 52 | var n = cls.createNamespace('out') 53 | , ee = new EventEmitter() 54 | ; 55 | 56 | ee.on('event', function () { 57 | t.equal(n.get('value'), 'hello', "value still set in EE."); 58 | cls.destroyNamespace('out'); 59 | }); 60 | 61 | n.run(function () { 62 | n.set('value', 'hello'); 63 | n.bindEmitter(ee); 64 | 65 | ee.emit('event'); 66 | }); 67 | }); 68 | 69 | t.test("once handler registered out of context", function (t) { 70 | t.plan(1); 71 | 72 | var n = cls.createNamespace('outOnce') 73 | , ee = new EventEmitter() 74 | ; 75 | 76 | ee.once('event', function () { 77 | t.equal(n.get('value'), 'hello', "value still set in EE."); 78 | cls.destroyNamespace('outOnce'); 79 | }); 80 | 81 | n.run(function () { 82 | n.set('value', 'hello'); 83 | n.bindEmitter(ee); 84 | 85 | ee.emit('event'); 86 | }); 87 | }); 88 | 89 | t.test("handler registered out of context, emit out of context", function (t) { 90 | t.plan(1); 91 | 92 | var n = cls.createNamespace('out') 93 | , ee = new EventEmitter() 94 | ; 95 | 96 | ee.on('event', function () { 97 | t.equal(n.get('value'), undefined, "no context."); 98 | cls.destroyNamespace('out'); 99 | }); 100 | 101 | n.run(function () { 102 | n.set('value', 'hello'); 103 | n.bindEmitter(ee); 104 | }); 105 | 106 | ee.emit('event'); 107 | }); 108 | 109 | t.test("once handler registered out of context on Readable", function (t) { 110 | var Readable = require('stream').Readable; 111 | 112 | if (Readable) { 113 | t.plan(12); 114 | 115 | var n = cls.createNamespace('outOnceReadable') 116 | , re = new Readable() 117 | ; 118 | 119 | re._read = function () {}; 120 | 121 | t.ok(n.name, "namespace has a name"); 122 | t.equal(n.name, 'outOnceReadable', "namespace has a name"); 123 | 124 | re.once('data', function (data) { 125 | t.equal(n.get('value'), 'hello', "value still set in EE"); 126 | t.equal(data, 'blah', "emit still works"); 127 | cls.destroyNamespace('outOnceReadable'); 128 | }); 129 | 130 | n.run(function () { 131 | n.set('value', 'hello'); 132 | 133 | t.notOk(re.emit.__wrapped, "emit is not wrapped"); 134 | t.notOk(re.on.__wrapped, "on is not wrapped"); 135 | t.notOk(re.addListener.__wrapped, "addListener is not wrapped"); 136 | 137 | n.bindEmitter(re); 138 | 139 | t.ok(re.emit.__wrapped, "emit is wrapped"); 140 | t.ok(re.on.__wrapped, "on is wrapped"); 141 | t.ok(re.addListener.__wrapped, "addListener is wrapped"); 142 | 143 | t.equal(typeof re._events.data, 'function', 'only the one data listener'); 144 | t.notOk(re._events.data['context@outOnceReadable'], "context isn't on listener"); 145 | 146 | re.emit('data', 'blah'); 147 | }); 148 | } 149 | else { 150 | t.comment("this test requires node 0.10+"); 151 | t.end(); 152 | } 153 | }); 154 | 155 | t.test("emitter with newListener that removes handler", function (t) { 156 | t.plan(3); 157 | 158 | var n = cls.createNamespace('newListener') 159 | , ee = new EventEmitter() 160 | ; 161 | 162 | // add monkeypatching to ee 163 | n.bindEmitter(ee); 164 | 165 | function listen() { 166 | ee.on('data', function (chunk) { 167 | t.equal(chunk, 'chunk', 'listener still works'); 168 | }); 169 | } 170 | 171 | ee.on('newListener', function handler(event) { 172 | if (event !== 'data') return; 173 | 174 | this.removeListener('newListener', handler); 175 | t.notOk(this.listeners('newListener').length, 'newListener was removed'); 176 | process.nextTick(listen); 177 | }); 178 | 179 | ee.on('drain', function (chunk) { 180 | process.nextTick(function () { 181 | ee.emit('data', chunk); 182 | }); 183 | }); 184 | 185 | ee.on('data', function (chunk) { 186 | t.equal(chunk, 'chunk', 'got data event'); 187 | cls.destroyNamespace('newListener'); 188 | }); 189 | 190 | ee.emit('drain', 'chunk'); 191 | }); 192 | 193 | t.test("handler registered in context on Readable", function (t) { 194 | var Readable = require('stream').Readable; 195 | 196 | if (Readable) { 197 | t.plan(12); 198 | 199 | var n = cls.createNamespace('outOnReadable') 200 | , re = new Readable() 201 | ; 202 | 203 | re._read = function () {}; 204 | 205 | t.ok(n.name, "namespace has a name"); 206 | t.equal(n.name, 'outOnReadable', "namespace has a name"); 207 | 208 | n.run(function () { 209 | n.set('value', 'hello'); 210 | 211 | n.bindEmitter(re); 212 | 213 | t.ok(re.emit.__wrapped, "emit is wrapped"); 214 | t.ok(re.on.__wrapped, "on is wrapped"); 215 | t.ok(re.addListener.__wrapped, "addListener is wrapped"); 216 | 217 | re.on('data', function (data) { 218 | t.equal(n.get('value'), 'hello', "value still set in EE"); 219 | t.equal(data, 'blah', "emit still works"); 220 | cls.destroyNamespace('outOnReadable'); 221 | }); 222 | }); 223 | 224 | t.ok(re.emit.__wrapped, "emit is still wrapped"); 225 | t.ok(re.on.__wrapped, "on is still wrapped"); 226 | t.ok(re.addListener.__wrapped, "addListener is still wrapped"); 227 | 228 | t.equal(typeof re._events.data, 'function', 'only the one data listener'); 229 | t.ok(re._events.data['cls@contexts']['context@outOnReadable'], 230 | "context is bound to listener"); 231 | 232 | re.emit('data', 'blah'); 233 | } 234 | else { 235 | t.comment("this test requires node 0.10+"); 236 | t.end(); 237 | } 238 | }); 239 | 240 | t.test("handler added but used entirely out of context", function (t) { 241 | t.plan(2); 242 | 243 | var n = cls.createNamespace('none') 244 | , ee = new EventEmitter() 245 | ; 246 | 247 | n.run(function () { 248 | n.set('value', 'hello'); 249 | n.bindEmitter(ee); 250 | }); 251 | 252 | ee.on('event', function () { 253 | t.ok(n, "n is set"); 254 | t.notOk(n.get('value'), "value shouldn't be visible"); 255 | cls.destroyNamespace('none'); 256 | }); 257 | 258 | ee.emit('event'); 259 | }); 260 | 261 | t.test("handler added but no listeners registered", function (t) { 262 | t.plan(3); 263 | 264 | var http = require('http') 265 | , n = cls.createNamespace('no_listener') 266 | ; 267 | 268 | // only fails on Node < 0.10 269 | var server = http.createServer(function (req, res) { 270 | n.bindEmitter(req); 271 | 272 | t.doesNotThrow(function () { 273 | req.emit('event'); 274 | }); 275 | 276 | res.writeHead(200, {"Content-Length" : 4}); 277 | res.end('WORD'); 278 | }); 279 | server.listen(8080); 280 | 281 | http.get('http://localhost:8080/', function (res) { 282 | t.equal(res.statusCode, 200, "request came back OK"); 283 | 284 | res.setEncoding('ascii'); 285 | res.on('data', function (body) { 286 | t.equal(body, 'WORD'); 287 | 288 | server.close(); 289 | cls.destroyNamespace('no_listener'); 290 | }); 291 | }); 292 | }); 293 | 294 | t.test("listener with parameters added but not bound to context", function (t) { 295 | t.plan(2); 296 | 297 | var ee = new EventEmitter() 298 | , n = cls.createNamespace('param_list') 299 | ; 300 | 301 | function sent(value) { 302 | t.equal(value, 3, "sent value is correct"); 303 | cls.destroyNamespace('param_list'); 304 | } 305 | 306 | ee.on('send', sent); 307 | n.bindEmitter(ee); 308 | t.doesNotThrow(function () { 309 | ee.emit('send', 3); 310 | }); 311 | }); 312 | 313 | t.test("listener that throws doesn't leave removeListener wrapped", function (t) { 314 | t.plan(4); 315 | 316 | var ee = new EventEmitter() 317 | , n = cls.createNamespace('kaboom') 318 | ; 319 | 320 | n.bindEmitter(ee); 321 | 322 | function kaboom() { 323 | throw new Error('whoops'); 324 | } 325 | 326 | n.run(function () { 327 | ee.on('bad', kaboom); 328 | 329 | t.throws(function () { ee.emit('bad'); }); 330 | t.equal(typeof ee.removeListener, 'function', 'removeListener is still there'); 331 | t.notOk(ee.removeListener.__wrapped, "removeListener got unwrapped"); 332 | t.equal(ee._events.bad, kaboom, "listener isn't still bound"); 333 | cls.destroyNamespace('kaboom'); 334 | }); 335 | }); 336 | 337 | t.test("emitter bound to multiple namespaces handles them correctly", function (t) { 338 | t.plan(8); 339 | 340 | var ee = new EventEmitter() 341 | , ns1 = cls.createNamespace('1') 342 | , ns2 = cls.createNamespace('2') 343 | ; 344 | 345 | // emulate an incoming data emitter 346 | setTimeout(function () { 347 | ee.emit('data', 'hi'); 348 | }, 10); 349 | 350 | t.doesNotThrow(function () { ns1.bindEmitter(ee); }); 351 | t.doesNotThrow(function () { ns2.bindEmitter(ee); }); 352 | 353 | ns1.run(function () { 354 | ns2.run(function () { 355 | ns1.set('name', 'tom1'); 356 | ns2.set('name', 'tom2'); 357 | 358 | t.doesNotThrow(function () { ns1.bindEmitter(ee); }); 359 | t.doesNotThrow(function () { ns2.bindEmitter(ee); }); 360 | 361 | ns1.run(function () { 362 | process.nextTick(function () { 363 | t.equal(ns1.get('name'), 'tom1', "ns1 value correct"); 364 | t.equal(ns2.get('name'), 'tom2', "ns2 value correct"); 365 | 366 | ns1.set('name', 'bob'); 367 | ns2.set('name', 'alice'); 368 | 369 | ee.on('data', function () { 370 | t.equal(ns1.get('name'), 'bob', "ns1 value bound onto emitter"); 371 | t.equal(ns2.get('name'), 'alice', "ns2 value bound onto emitter"); 372 | }); 373 | }); 374 | }); 375 | }); 376 | }); 377 | }); 378 | }); 379 | -------------------------------------------------------------------------------- /test/bind.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // stdlib 4 | var tap = require('tap'); 5 | var test = tap.test; 6 | var EventEmitter = require('events').EventEmitter; 7 | 8 | // module under test 9 | var context = require('../context.js'); 10 | 11 | // multiple contexts in use 12 | var tracer = context.createNamespace('tracer'); 13 | 14 | function Trace(harvester) { 15 | this.harvester = harvester; 16 | } 17 | 18 | Trace.prototype.runHandler = function (callback) { 19 | var wrapped = tracer.bind(function () { 20 | callback(); 21 | this.harvester.emit('finished', tracer.get('transaction')); 22 | }.bind(this)); 23 | wrapped(); 24 | }; 25 | 26 | 27 | test("simple tracer built on contexts", function (t) { 28 | t.plan(6); 29 | 30 | var harvester = new EventEmitter(); 31 | var trace = new Trace(harvester); 32 | 33 | harvester.on('finished', function (transaction) { 34 | t.ok(transaction, "transaction should have been passed in"); 35 | t.equal(transaction.status, 'ok', "transaction should have finished OK"); 36 | t.equal(Object.keys(process.namespaces).length, 1, "Should only have one namespace."); 37 | }); 38 | 39 | trace.runHandler(function inScope() { 40 | t.ok(tracer.active, "tracer should have an active context"); 41 | tracer.set('transaction', {status : 'ok'}); 42 | t.ok(tracer.get('transaction'), "can retrieve newly-set value"); 43 | t.equal(tracer.get('transaction').status, 'ok', "value should be correct"); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/crypto.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var tap = require('tap') 4 | , semver = require('semver') 5 | , test = tap.test 6 | , createNamespace = require('../context.js').createNamespace 7 | ; 8 | 9 | var crypto; 10 | try { crypto = require('crypto'); } 11 | catch (err) {} 12 | 13 | if (crypto) { 14 | test("continuation-local state with crypto.randomBytes", function (t) { 15 | t.plan(1); 16 | 17 | var namespace = createNamespace('namespace'); 18 | namespace.run(function () { 19 | namespace.set('test', 0xabad1dea); 20 | 21 | t.test("randomBytes", function (t) { 22 | namespace.run(function () { 23 | namespace.set('test', 42); 24 | crypto.randomBytes(100, function (err) { 25 | if (err) throw err; 26 | t.equal(namespace.get('test'), 42, "mutated state was preserved"); 27 | t.end(); 28 | }); 29 | }); 30 | }); 31 | }); 32 | }); 33 | 34 | test("continuation-local state with crypto.pseudoRandomBytes", function (t) { 35 | t.plan(1); 36 | 37 | var namespace = createNamespace('namespace'); 38 | namespace.run(function () { 39 | namespace.set('test', 0xabad1dea); 40 | 41 | t.test("pseudoRandomBytes", function (t) { 42 | namespace.run(function () { 43 | namespace.set('test', 42); 44 | crypto.pseudoRandomBytes(100, function (err) { 45 | if (err) throw err; 46 | t.equal(namespace.get('test'), 42, "mutated state was preserved"); 47 | t.end(); 48 | }); 49 | }); 50 | }); 51 | }); 52 | }); 53 | 54 | test("continuation-local state with crypto.pbkdf2", function (t) { 55 | t.plan(1); 56 | 57 | var namespace = createNamespace('namespace'); 58 | namespace.run(function () { 59 | namespace.set('test', 0xabad1dea); 60 | 61 | t.test("pbkdf2", function (t) { 62 | namespace.run(function () { 63 | namespace.set('test', 42); 64 | // this API changed after 0.10.0, and errors if digest is missing after v6 65 | if (semver.gte(process.version, "0.12.0")) { 66 | crypto.pbkdf2("s3cr3tz", "451243", 10, 40, "sha512", function (err) { 67 | if (err) throw err; 68 | t.equal(namespace.get('test'), 42, "mutated state was preserved"); 69 | t.end(); 70 | }); 71 | } else { 72 | crypto.pbkdf2("s3cr3tz", "451243", 10, 40, function (err) { 73 | if (err) throw err; 74 | t.equal(namespace.get('test'), 42, "mutated state was preserved"); 75 | t.end(); 76 | }); 77 | } 78 | }); 79 | }); 80 | }); 81 | }); 82 | } 83 | -------------------------------------------------------------------------------- /test/dns.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var dns = require('dns') 4 | , tap = require('tap') 5 | , test = tap.test 6 | , createNamespace = require('../context.js').createNamespace 7 | ; 8 | 9 | test("continuation-local state with MakeCallback and DNS module", function (t) { 10 | t.plan(11); 11 | 12 | var namespace = createNamespace('dns'); 13 | namespace.run(function () { 14 | namespace.set('test', 0xabad1dea); 15 | 16 | t.test("dns.lookup", function (t) { 17 | namespace.run(function () { 18 | namespace.set('test', 808); 19 | t.equal(namespace.get('test'), 808, "state has been mutated"); 20 | 21 | dns.lookup('www.newrelic.com', 4, function (err, addresses) { 22 | t.notOk(err, "lookup succeeded"); 23 | t.ok(addresses.length > 0, "some results were found"); 24 | 25 | t.equal(namespace.get('test'), 808, 26 | "mutated state has persisted to dns.lookup's callback"); 27 | 28 | t.end(); 29 | }); 30 | }); 31 | }); 32 | 33 | t.test("dns.resolve", function (t) { 34 | namespace.run(function () { 35 | namespace.set('test', 909); 36 | t.equal(namespace.get('test'), 909, "state has been mutated"); 37 | 38 | dns.resolve('newrelic.com', 'NS', function (err, addresses) { 39 | t.notOk(err, "lookup succeeded"); 40 | t.ok(addresses.length > 0, "some results were found"); 41 | 42 | t.equal(namespace.get('test'), 909, 43 | "mutated state has persisted to dns.resolve's callback"); 44 | 45 | t.end(); 46 | }); 47 | }); 48 | }); 49 | 50 | t.test("dns.resolve4", function (t) { 51 | namespace.run(function () { 52 | namespace.set('test', 303); 53 | t.equal(namespace.get('test'), 303, "state has been mutated"); 54 | 55 | dns.resolve4('www.newrelic.com', function (err, addresses) { 56 | t.notOk(err, "lookup succeeded"); 57 | t.ok(addresses.length > 0, "some results were found"); 58 | 59 | t.equal(namespace.get('test'), 303, 60 | "mutated state has persisted to dns.resolve4's callback"); 61 | 62 | t.end(); 63 | }); 64 | }); 65 | }); 66 | 67 | t.test("dns.resolve6", function (t) { 68 | namespace.run(function () { 69 | namespace.set('test', 101); 70 | t.equal(namespace.get('test'), 101, "state has been mutated"); 71 | 72 | dns.resolve6('google.com', function (err, addresses) { 73 | t.notOk(err, "lookup succeeded"); 74 | t.ok(addresses.length > 0, "some results were found"); 75 | 76 | t.equal(namespace.get('test'), 101, 77 | "mutated state has persisted to dns.resolve6's callback"); 78 | 79 | t.end(); 80 | }); 81 | }); 82 | }); 83 | 84 | t.test("dns.resolveCname", function (t) { 85 | namespace.run(function () { 86 | namespace.set('test', 212); 87 | t.equal(namespace.get('test'), 212, "state has been mutated"); 88 | 89 | dns.resolveCname('mail.newrelic.com', function (err, addresses) { 90 | t.notOk(err, "lookup succeeded"); 91 | t.ok(addresses.length > 0, "some results were found"); 92 | 93 | t.equal(namespace.get('test'), 212, 94 | "mutated state has persisted to dns.resolveCname's callback"); 95 | 96 | t.end(); 97 | }); 98 | }); 99 | }); 100 | 101 | t.test("dns.resolveMx", function (t) { 102 | namespace.run(function () { 103 | namespace.set('test', 707); 104 | t.equal(namespace.get('test'), 707, "state has been mutated"); 105 | 106 | dns.resolveMx('newrelic.com', function (err, addresses) { 107 | t.notOk(err, "lookup succeeded"); 108 | t.ok(addresses.length > 0, "some results were found"); 109 | 110 | t.equal(namespace.get('test'), 707, 111 | "mutated state has persisted to dns.resolveMx's callback"); 112 | 113 | t.end(); 114 | }); 115 | }); 116 | }); 117 | 118 | t.test("dns.resolveNs", function (t) { 119 | namespace.run(function () { 120 | namespace.set('test', 717); 121 | t.equal(namespace.get('test'), 717, "state has been mutated"); 122 | 123 | dns.resolveNs('newrelic.com', function (err, addresses) { 124 | t.notOk(err, "lookup succeeded"); 125 | t.ok(addresses.length > 0, "some results were found"); 126 | 127 | t.equal(namespace.get('test'), 717, 128 | "mutated state has persisted to dns.resolveNs's callback"); 129 | 130 | t.end(); 131 | }); 132 | }); 133 | }); 134 | 135 | t.test("dns.resolveTxt", function (t) { 136 | namespace.run(function () { 137 | namespace.set('test', 2020); 138 | t.equal(namespace.get('test'), 2020, "state has been mutated"); 139 | 140 | dns.resolveTxt('newrelic.com', function (err, addresses) { 141 | t.notOk(err, "lookup succeeded"); 142 | t.ok(addresses.length > 0, "some results were found"); 143 | 144 | t.equal(namespace.get('test'), 2020, 145 | "mutated state has persisted to dns.resolveTxt's callback"); 146 | 147 | t.end(); 148 | }); 149 | }); 150 | }); 151 | 152 | t.test("dns.resolveSrv", function (t) { 153 | namespace.run(function () { 154 | namespace.set('test', 9000); 155 | t.equal(namespace.get('test'), 9000, "state has been mutated"); 156 | 157 | dns.resolveSrv('_xmpp-server._tcp.google.com', function (err, addresses) { 158 | t.notOk(err, "lookup succeeded"); 159 | t.ok(addresses.length > 0, "some results were found"); 160 | 161 | t.equal(namespace.get('test'), 9000, 162 | "mutated state has persisted to dns.resolveSrv's callback"); 163 | 164 | t.end(); 165 | }); 166 | }); 167 | }); 168 | 169 | t.test("dns.resolveNaptr", function (t) { 170 | // dns.resolveNaptr only in Node > 0.9.x 171 | if (!dns.resolveNaptr) return t.end(); 172 | 173 | namespace.run(function () { 174 | namespace.set('test', 'Polysix'); 175 | t.equal(namespace.get('test'), 'Polysix', "state has been mutated"); 176 | 177 | dns.resolveNaptr('columbia.edu', function (err, addresses) { 178 | t.notOk(err, "lookup succeeded"); 179 | t.ok(addresses.length > 0, "some results were found"); 180 | 181 | t.equal(namespace.get('test'), 'Polysix', 182 | "mutated state has persisted to dns.resolveNaptr's callback"); 183 | 184 | t.end(); 185 | }); 186 | }); 187 | }); 188 | 189 | t.test("dns.reverse", function (t) { 190 | namespace.run(function () { 191 | namespace.set('test', 1000); 192 | t.equal(namespace.get('test'), 1000, "state has been mutated"); 193 | 194 | dns.reverse('204.93.223.144', function (err, addresses) { 195 | t.notOk(err, "lookup succeeded"); 196 | t.ok(addresses.length > 0, "some results were found"); 197 | 198 | t.equal(namespace.get('test'), 1000, 199 | "mutated state has persisted to dns.reverse's callback"); 200 | 201 | t.end(); 202 | }); 203 | }); 204 | }); 205 | }); 206 | }); 207 | -------------------------------------------------------------------------------- /test/error-handling.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var test = require('tap').test 4 | , cls = require('../context.js') 5 | , domain = require('domain') 6 | ; 7 | 8 | test("continuation-local storage glue with a throw in the continuation chain", 9 | function (t) { 10 | var namespace = cls.createNamespace('test'); 11 | namespace.run(function () { 12 | var d = domain.create(); 13 | namespace.set('outer', true); 14 | namespace.bindEmitter(d); 15 | 16 | d.on('error', function (blerg) { 17 | t.equal(blerg.message, "explicitly nonlocal exit", "got the expected exception"); 18 | t.ok(namespace.get('outer'), "outer context is still active"); 19 | t.notOk(namespace.get('inner'), "inner context should have been exited by throw"); 20 | t.equal(namespace._set.length, 1, "should be back to outer state"); 21 | 22 | cls.destroyNamespace('test'); 23 | t.end(); 24 | }); 25 | 26 | // tap is only trying to help 27 | process.nextTick(d.bind(function () { 28 | t.ok(namespace.get('outer'), "outer mutation worked"); 29 | t.notOk(namespace.get('inner'), "inner mutation hasn't happened yet"); 30 | 31 | namespace.run(function () { 32 | namespace.set('inner', true); 33 | throw new Error("explicitly nonlocal exit"); 34 | }); 35 | })); 36 | }); 37 | }); 38 | 39 | test("synchronous throw attaches the context", function (t) { 40 | t.plan(3); 41 | 42 | var namespace = cls.createNamespace('cls@synchronous'); 43 | namespace.run(function () { 44 | namespace.set('value', 'transaction clear'); 45 | try { 46 | namespace.run(function () { 47 | namespace.set('value', 'transaction set'); 48 | throw new Error('cls@synchronous explosion'); 49 | }); 50 | } 51 | catch (e) { 52 | t.ok(namespace.fromException(e), "context was attached to error"); 53 | t.equal(namespace.fromException(e)['value'], 'transaction set', 54 | "found the inner value"); 55 | } 56 | 57 | t.equal(namespace.get('value'), 'transaction clear', "everything was reset"); 58 | }); 59 | 60 | cls.destroyNamespace('cls@synchronous'); 61 | }); 62 | 63 | test("synchronous throw checks if error exists", function (t) { 64 | t.plan(2); 65 | 66 | var namespace = cls.createNamespace('cls@synchronous-null-error'); 67 | namespace.run(function () { 68 | namespace.set('value', 'transaction clear'); 69 | try { 70 | namespace.run(function () { 71 | namespace.set('value', 'transaction set'); 72 | throw null; 73 | }); 74 | } 75 | catch (e) { 76 | // as we had a null error, cls couldn't set the new inner value 77 | t.equal(namespace.get('value'), 'transaction clear', 'from outer value'); 78 | } 79 | 80 | t.equal(namespace.get('value'), 'transaction clear', "everything was reset"); 81 | }); 82 | 83 | cls.destroyNamespace('cls@synchronous-null-error'); 84 | }); 85 | 86 | test("throw in process.nextTick attaches the context", function (t) { 87 | t.plan(3); 88 | 89 | var namespace = cls.createNamespace('cls@nexttick'); 90 | var d = domain.create(); 91 | namespace.bindEmitter(d); 92 | 93 | d.on('error', function (e) { 94 | t.ok(namespace.fromException(e), "context was attached to error"); 95 | t.equal(namespace.fromException(e)['value'], 'transaction set', 96 | "found the inner value"); 97 | 98 | cls.destroyNamespace('cls@nexttick'); 99 | }); 100 | 101 | namespace.run(function () { 102 | namespace.set('value', 'transaction clear'); 103 | 104 | // tap is only trying to help 105 | process.nextTick(d.bind(function () { 106 | namespace.run(function () { 107 | namespace.set('value', 'transaction set'); 108 | throw new Error("cls@nexttick explosion"); 109 | }); 110 | })); 111 | 112 | t.equal(namespace.get('value'), 'transaction clear', "everything was reset"); 113 | }); 114 | }); 115 | 116 | test("throw in setTimeout attaches the context", function (t) { 117 | t.plan(3); 118 | 119 | var namespace = cls.createNamespace('cls@setTimeout'); 120 | var d = domain.create(); 121 | namespace.bindEmitter(d); 122 | 123 | d.on('error', function (e) { 124 | t.ok(namespace.fromException(e), "context was attached to error"); 125 | t.equal(namespace.fromException(e)['value'], 'transaction set', 126 | "found the inner value"); 127 | 128 | cls.destroyNamespace('cls@setTimeout'); 129 | }); 130 | 131 | namespace.run(function () { 132 | namespace.set('value', 'transaction clear'); 133 | 134 | // tap is only trying to help 135 | setTimeout(d.bind(function () { 136 | namespace.run(function () { 137 | namespace.set('value', 'transaction set'); 138 | throw new Error("cls@setTimeout explosion"); 139 | }); 140 | })); 141 | 142 | t.equal(namespace.get('value'), 'transaction clear', "everything was reset"); 143 | }); 144 | }); 145 | -------------------------------------------------------------------------------- /test/fs.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var createNamespace = require('../context.js').createNamespace 4 | , fs = require('fs') 5 | , path = require('path') 6 | , exec = require('child_process').exec 7 | , tap = require('tap') 8 | , test = tap.test 9 | ; 10 | 11 | // CONSTANTS 12 | var FILENAME = '__testfile' 13 | , DIRNAME = '__TESTDIR' 14 | , LINKNAME = '__testlink' 15 | , HARDLINKNAME = '__testhardlink' 16 | ; 17 | 18 | function createFile(assert) { 19 | var contents = new Buffer("UHOH") 20 | , file = fs.openSync(FILENAME, 'w') 21 | , written = fs.writeSync(file, contents, 0, contents.length, 0) 22 | ; 23 | assert.equals(written, contents.length, "whole buffer was written"); 24 | var rc = fs.closeSync(file); 25 | // need this here to avoid dealing with umask complications 26 | fs.chmodSync(FILENAME, '0666'); 27 | return rc; 28 | } 29 | 30 | function deleteFile() { return fs.unlinkSync(FILENAME); } 31 | 32 | 33 | function createLink(assert) { 34 | createFile(assert); 35 | fs.symlinkSync(FILENAME, LINKNAME); 36 | if (fs.lchmodSync) { 37 | // This function only exists on BSD systems (like OSX) 38 | fs.lchmodSync(LINKNAME, '0777'); 39 | } 40 | } 41 | 42 | function deleteLink() { 43 | fs.unlinkSync(LINKNAME); 44 | return deleteFile(); 45 | } 46 | 47 | 48 | function createDirectory(assert) { 49 | fs.mkdirSync(DIRNAME); 50 | assert.ok(fs.existsSync(DIRNAME), "directory was created"); 51 | } 52 | 53 | function deleteDirectory() { return fs.rmdirSync(DIRNAME); } 54 | 55 | 56 | function mapIds(username, groupname, callback) { 57 | if (!callback) throw new Error("mapIds requires callback"); 58 | if (!username) return callback(new Error("mapIds requires username")); 59 | if (!groupname) return callback(new Error("mapIds requires groupname")); 60 | 61 | exec('id -u ' + username, function (error, stdout, stderr) { 62 | if (error) return callback(error); 63 | if (stderr) return callback(new Error(stderr)); 64 | 65 | var uid = +stdout; 66 | exec('id -g ' + groupname, function (error, stdout, stderr) { 67 | if (error) return callback(error); 68 | if (stderr) return callback(new Error(stderr)); 69 | 70 | var gid = +stdout; 71 | callback(null, uid, gid); 72 | }); 73 | }); 74 | } 75 | 76 | test("continuation-local state with MakeCallback and fs module", function (t) { 77 | t.plan(33); 78 | 79 | var namespace = createNamespace('fs'); 80 | namespace.run(function () { 81 | namespace.set('test', 0xabad1dea); 82 | t.test("fs.rename", function (t) { 83 | createFile(t); 84 | 85 | namespace.run(function () { 86 | namespace.set('test', 'rename'); 87 | t.equal(namespace.get('test'), 'rename', "state has been mutated"); 88 | 89 | fs.rename(FILENAME, '__renamed', function (error) { 90 | t.notOk(error, "renaming shouldn't error"); 91 | t.equal(namespace.get('test'), 'rename', 92 | "mutated state has persisted to fs.rename's callback"); 93 | 94 | fs.unlinkSync('__renamed'); 95 | t.end(); 96 | }); 97 | }); 98 | }); 99 | 100 | t.test("fs.truncate", function (t) { 101 | // truncate -> ftruncate in Node > 0.8.x 102 | if (!fs.ftruncate) return t.end(); 103 | 104 | createFile(t); 105 | 106 | namespace.run(function () { 107 | namespace.set('test', 'truncate'); 108 | t.equal(namespace.get('test'), 'truncate', "state has been mutated"); 109 | 110 | fs.truncate(FILENAME, 0, function (error) { 111 | t.notOk(error, "truncation shouldn't error"); 112 | 113 | var stats = fs.statSync(FILENAME); 114 | t.equal(stats.size, 0, "file has been truncated"); 115 | 116 | t.equal(namespace.get('test'), 'truncate', 117 | "mutated state has persisted to fs.truncate's callback"); 118 | 119 | deleteFile(); 120 | t.end(); 121 | }); 122 | }); 123 | }); 124 | 125 | t.test("fs.ftruncate", function (t) { 126 | createFile(t); 127 | 128 | // truncate -> ftruncate in Node > 0.8.x 129 | var truncate = fs.ftruncate ? fs.ftruncate : fs.truncate; 130 | 131 | namespace.run(function () { 132 | namespace.set('test', 'ftruncate'); 133 | t.equal(namespace.get('test'), 'ftruncate', "state has been mutated"); 134 | 135 | var file = fs.openSync(FILENAME, 'w'); 136 | truncate(file, 0, function (error) { 137 | t.notOk(error, "truncation shouldn't error"); 138 | 139 | fs.closeSync(file); 140 | var stats = fs.statSync(FILENAME); 141 | t.equal(stats.size, 0, "file has been truncated"); 142 | 143 | t.equal(namespace.get('test'), 'ftruncate', 144 | "mutated state has persisted to fs.ftruncate's callback"); 145 | 146 | deleteFile(); 147 | t.end(); 148 | }); 149 | }); 150 | }); 151 | 152 | t.test("fs.chown", function (t) { 153 | createFile(t); 154 | 155 | mapIds('daemon', 'daemon', function (error, uid, gid) { 156 | t.notOk(error, "looking up uid & gid shouldn't error"); 157 | t.ok(uid, "uid for daemon was found"); 158 | t.ok(gid, "gid for daemon was found"); 159 | 160 | namespace.run(function () { 161 | namespace.set('test', 'chown'); 162 | t.equal(namespace.get('test'), 'chown', "state has been mutated"); 163 | 164 | fs.chown(FILENAME, uid, gid, function (error) { 165 | t.ok(error, "changing ownership will error for non-root users"); 166 | 167 | t.equal(namespace.get('test'), 'chown', 168 | "mutated state has persisted to fs.chown's callback"); 169 | 170 | deleteFile(); 171 | t.end(); 172 | }); 173 | }); 174 | }); 175 | }); 176 | 177 | t.test("fs.fchown", function (t) { 178 | createFile(t); 179 | 180 | mapIds('daemon', 'daemon', function (error, uid, gid) { 181 | t.notOk(error, "looking up uid & gid shouldn't error"); 182 | t.ok(uid, "uid for daemon was found"); 183 | t.ok(gid, "gid for daemon was found"); 184 | 185 | namespace.run(function () { 186 | namespace.set('test', 'fchown'); 187 | t.equal(namespace.get('test'), 'fchown', "state has been mutated"); 188 | 189 | var file = fs.openSync(FILENAME, 'w'); 190 | fs.fchown(file, uid, gid, function (error) { 191 | t.ok(error, "changing ownership will error for non-root users"); 192 | 193 | t.equal(namespace.get('test'), 'fchown', 194 | "mutated state has persisted to fs.fchown's callback"); 195 | 196 | fs.closeSync(file); 197 | deleteFile(); 198 | t.end(); 199 | }); 200 | }); 201 | }); 202 | }); 203 | 204 | t.test("fs.lchown", function (t) { 205 | if (!fs.lchown) return t.end(); 206 | createLink(t); 207 | 208 | mapIds('daemon', 'daemon', function (error, uid, gid) { 209 | t.notOk(error, "looking up uid & gid shouldn't error"); 210 | t.ok(uid, "uid for daemon was found"); 211 | t.ok(gid, "gid for daemon was found"); 212 | 213 | namespace.run(function () { 214 | namespace.set('test', 'lchown'); 215 | t.equal(namespace.get('test'), 'lchown', "state has been mutated"); 216 | 217 | fs.lchown(LINKNAME, uid, gid, function (error) { 218 | t.ok(error, "changing ownership will error for non-root users"); 219 | 220 | t.equal(namespace.get('test'), 'lchown', 221 | "mutated state has persisted to fs.lchown's callback"); 222 | 223 | deleteLink(); 224 | t.end(); 225 | }); 226 | }); 227 | }); 228 | }); 229 | 230 | t.test("fs.chmod", function (t) { 231 | createFile(t); 232 | 233 | namespace.run(function () { 234 | namespace.set('test', 'chmod'); 235 | t.equal(namespace.get('test'), 'chmod', "state has been mutated"); 236 | 237 | fs.chmod(FILENAME, '0700', function (error) { 238 | t.notOk(error, "changing mode shouldn't error"); 239 | 240 | t.equal(namespace.get('test'), 'chmod', 241 | "mutated state has persisted to fs.chmod's callback"); 242 | 243 | var stats = fs.statSync(FILENAME); 244 | t.equal(stats.mode.toString(8), '100700', "extra access bits are stripped"); 245 | 246 | deleteFile(); 247 | t.end(); 248 | }); 249 | }); 250 | }); 251 | 252 | t.test("fs.fchmod", function (t) { 253 | createFile(t); 254 | 255 | namespace.run(function () { 256 | namespace.set('test', 'fchmod'); 257 | t.equal(namespace.get('test'), 'fchmod', "state has been mutated"); 258 | 259 | var file = fs.openSync(FILENAME, 'w+'); 260 | fs.fchmod(file, '0700', function (error) { 261 | t.notOk(error, "changing mode shouldn't error"); 262 | 263 | t.equal(namespace.get('test'), 'fchmod', 264 | "mutated state has persisted to fs.fchmod's callback"); 265 | 266 | fs.closeSync(file); 267 | var stats = fs.statSync(FILENAME); 268 | t.equal(stats.mode.toString(8), '100700', "extra access bits are stripped"); 269 | 270 | deleteFile(); 271 | t.end(); 272 | }); 273 | }); 274 | }); 275 | 276 | t.test("fs.lchmod", function (t) { 277 | if (!fs.lchmod) return t.end(); 278 | createLink(t); 279 | 280 | namespace.run(function () { 281 | namespace.set('test', 'lchmod'); 282 | t.equal(namespace.get('test'), 'lchmod', "state has been mutated"); 283 | 284 | fs.lchmod(LINKNAME, '0700', function (error) { 285 | t.notOk(error, "changing mode shouldn't error"); 286 | 287 | t.equal(namespace.get('test'), 'lchmod', 288 | "mutated state has persisted to fs.lchmod's callback"); 289 | 290 | var stats = fs.lstatSync(LINKNAME); 291 | t.equal(stats.mode.toString(8), '120700', "extra access bits are stripped"); 292 | 293 | deleteLink(); 294 | t.end(); 295 | }); 296 | }); 297 | }); 298 | 299 | t.test("fs.stat", function (t) { 300 | createFile(t); 301 | 302 | namespace.run(function () { 303 | namespace.set('test', 'stat'); 304 | t.equal(namespace.get('test'), 'stat', "state has been mutated"); 305 | 306 | fs.stat(FILENAME, function (error, stats) { 307 | t.notOk(error, "reading stats shouldn't error"); 308 | 309 | t.equal(namespace.get('test'), 'stat', 310 | "mutated state has persisted to fs.stat's callback"); 311 | 312 | t.equal(stats.mode.toString(8), '100666', "permissions should be as created"); 313 | 314 | deleteFile(); 315 | t.end(); 316 | }); 317 | }); 318 | }); 319 | 320 | t.test("fs.fstat", function (t) { 321 | createFile(t); 322 | 323 | namespace.run(function () { 324 | namespace.set('test', 'fstat'); 325 | t.equal(namespace.get('test'), 'fstat', "state has been mutated"); 326 | 327 | var file = fs.openSync(FILENAME, 'r'); 328 | fs.fstat(file, function (error, stats) { 329 | t.notOk(error, "reading stats shouldn't error"); 330 | 331 | t.equal(namespace.get('test'), 'fstat', 332 | "mutated state has persisted to fs.fstat's callback"); 333 | 334 | t.equal(stats.mode.toString(8), '100666', "permissions should be as created"); 335 | 336 | fs.closeSync(file); 337 | deleteFile(); 338 | t.end(); 339 | }); 340 | }); 341 | }); 342 | 343 | t.test("fs.lstat", function (t) { 344 | createLink(t); 345 | 346 | namespace.run(function () { 347 | namespace.set('test', 'lstat'); 348 | t.equal(namespace.get('test'), 'lstat', "state has been mutated"); 349 | 350 | fs.lstat(LINKNAME, function (error, stats) { 351 | t.notOk(error, "reading stats shouldn't error"); 352 | 353 | t.equal(namespace.get('test'), 'lstat', 354 | "mutated state has persisted to fs.lstat's callback"); 355 | 356 | t.equal( 357 | stats.mode.toString(8), 358 | '120777', 359 | "permissions should be as created" 360 | ); 361 | 362 | deleteLink(); 363 | t.end(); 364 | }); 365 | }); 366 | }); 367 | 368 | t.test("fs.link", function (t) { 369 | createFile(t); 370 | 371 | namespace.run(function () { 372 | namespace.set('test', 'link'); 373 | t.equal(namespace.get('test'), 'link', "state has been mutated"); 374 | 375 | fs.link(FILENAME, HARDLINKNAME, function (error) { 376 | t.notOk(error, "creating a link shouldn't error"); 377 | 378 | t.equal(namespace.get('test'), 'link', 379 | "mutated state has persisted to fs.link's callback"); 380 | 381 | var orig = fs.statSync(FILENAME) 382 | , linked = fs.statSync(HARDLINKNAME) 383 | ; 384 | t.equal(orig.ino, linked.ino, "entries should point to same file"); 385 | 386 | t.notOk(fs.unlinkSync(HARDLINKNAME), "link has been removed"); 387 | deleteFile(); 388 | t.end(); 389 | }); 390 | }); 391 | }); 392 | 393 | t.test("fs.symlink", function (t) { 394 | createFile(t); 395 | 396 | namespace.run(function () { 397 | namespace.set('test', 'symlink'); 398 | t.equal(namespace.get('test'), 'symlink', "state has been mutated"); 399 | 400 | fs.symlink(FILENAME, LINKNAME, function (error) { 401 | t.notOk(error, "creating a symlink shouldn't error"); 402 | 403 | t.equal(namespace.get('test'), 'symlink', 404 | "mutated state has persisted to fs.symlink's callback"); 405 | 406 | var pointed = fs.readlinkSync(LINKNAME); 407 | t.equal(pointed, FILENAME, "symlink points back to original file"); 408 | 409 | t.notOk(fs.unlinkSync(LINKNAME), "symlink has been removed"); 410 | deleteFile(); 411 | t.end(); 412 | }); 413 | }); 414 | }); 415 | 416 | t.test("fs.readlink", function (t) { 417 | createLink(t); 418 | 419 | namespace.run(function () { 420 | namespace.set('test', 'readlink'); 421 | t.equal(namespace.get('test'), 'readlink', "state has been mutated"); 422 | 423 | fs.readlink(LINKNAME, function (error, pointed) { 424 | t.notOk(error, "reading symlink shouldn't error"); 425 | 426 | t.equal(namespace.get('test'), 'readlink', 427 | "mutated state has persisted to fs.readlink's callback"); 428 | 429 | t.equal(pointed, FILENAME, "symlink points back to original file"); 430 | 431 | deleteLink(); 432 | t.end(); 433 | }); 434 | }); 435 | }); 436 | 437 | t.test("fs.unlink", function (t) { 438 | createFile(t); 439 | 440 | namespace.run(function () { 441 | namespace.set('test', 'unlink'); 442 | t.equal(namespace.get('test'), 'unlink', "state has been mutated"); 443 | 444 | fs.unlink(FILENAME, function (error) { 445 | t.notOk(error, "deleting file shouldn't error"); 446 | 447 | t.equal(namespace.get('test'), 'unlink', 448 | "mutated state has persisted to fs.unlink's callback"); 449 | 450 | t.notOk(fs.exists(FILENAME), "file should be gone"); 451 | t.end(); 452 | }); 453 | }); 454 | }); 455 | 456 | t.test("fs.realpath", function (t) { 457 | createFile(t); 458 | 459 | namespace.run(function () { 460 | namespace.set('test', 'realpath'); 461 | t.equal(namespace.get('test'), 'realpath', "state has been mutated"); 462 | 463 | fs.realpath(FILENAME, function (error, real) { 464 | t.notOk(error, "deleting file shouldn't error"); 465 | 466 | t.equal(namespace.get('test'), 'realpath', 467 | "mutated state has persisted to fs.realpath's callback"); 468 | 469 | t.equal(real, path.resolve(FILENAME), "no funny business with the real path"); 470 | 471 | deleteFile(); 472 | t.end(); 473 | }); 474 | }); 475 | }); 476 | 477 | t.test("fs.mkdir", function (t) { 478 | namespace.run(function () { 479 | namespace.set('test', 'mkdir'); 480 | t.equal(namespace.get('test'), 'mkdir', "state has been mutated"); 481 | 482 | fs.mkdir(DIRNAME, function (error) { 483 | t.notOk(error, "creating directory shouldn't error"); 484 | 485 | t.equal(namespace.get('test'), 'mkdir', 486 | "mutated state has persisted to fs.mkdir's callback"); 487 | 488 | t.ok(fs.existsSync(DIRNAME), "directory was created"); 489 | 490 | fs.rmdirSync(DIRNAME); 491 | t.end(); 492 | }); 493 | }); 494 | }); 495 | 496 | t.test("fs.rmdir", function (t) { 497 | createDirectory(t); 498 | 499 | namespace.run(function () { 500 | namespace.set('test', 'rmdir'); 501 | t.equal(namespace.get('test'), 'rmdir', "state has been mutated"); 502 | 503 | fs.rmdir(DIRNAME, function (error) { 504 | t.notOk(error, "deleting directory shouldn't error"); 505 | 506 | t.equal(namespace.get('test'), 'rmdir', 507 | "mutated state has persisted to fs.rmdir's callback"); 508 | 509 | t.notOk(fs.existsSync(DIRNAME), "directory was removed"); 510 | 511 | t.end(); 512 | }); 513 | }); 514 | }); 515 | 516 | t.test("fs.readdir", function (t) { 517 | createDirectory(t); 518 | 519 | var file1 = fs.openSync(path.join(DIRNAME, 'file1'), 'w'); 520 | fs.writeSync(file1, 'one'); 521 | fs.closeSync(file1); 522 | 523 | var file2 = fs.openSync(path.join(DIRNAME, 'file2'), 'w'); 524 | fs.writeSync(file2, 'two'); 525 | fs.closeSync(file2); 526 | 527 | var file3 = fs.openSync(path.join(DIRNAME, 'file3'), 'w'); 528 | fs.writeSync(file3, 'three'); 529 | fs.closeSync(file3); 530 | 531 | namespace.run(function () { 532 | namespace.set('test', 'readdir'); 533 | t.equal(namespace.get('test'), 'readdir', "state has been mutated"); 534 | 535 | fs.readdir(DIRNAME, function (error, contents) { 536 | t.notOk(error, "reading directory shouldn't error"); 537 | 538 | t.equal(namespace.get('test'), 'readdir', 539 | "mutated state has persisted to fs.readdir's callback"); 540 | 541 | t.equal(contents.length, 3, "3 files were found"); 542 | 543 | fs.unlinkSync(path.join(DIRNAME, 'file1')); 544 | fs.unlinkSync(path.join(DIRNAME, 'file2')); 545 | fs.unlinkSync(path.join(DIRNAME, 'file3')); 546 | deleteDirectory(); 547 | t.end(); 548 | }); 549 | }); 550 | }); 551 | 552 | t.test("fs.watch", function (t) { 553 | createFile(t); 554 | 555 | namespace.run(function () { 556 | namespace.set('test', 'watch'); 557 | t.equal(namespace.get('test'), 'watch', "state has been mutated"); 558 | 559 | var watcher = fs.watch(FILENAME, 560 | {persistent : false, interval : 200}, 561 | function (event) { 562 | t.equal(namespace.get('test'), 'watch', 563 | "mutated state has persisted to fs.watch's callback"); 564 | 565 | t.equal(event, 'change', "file was changed"); 566 | 567 | watcher.close(); 568 | process.nextTick(function cleanup() { 569 | deleteFile(); 570 | t.end(); 571 | }); 572 | }); 573 | 574 | setTimeout(function poke() { 575 | fs.writeFileSync(FILENAME, 'still a test'); 576 | }, 20); 577 | }); 578 | }); 579 | 580 | t.test("fs.utimes", function (t) { 581 | createFile(t); 582 | 583 | /* utimes(2) takes seconds since the epoch, and Date() deals with 584 | * milliseconds. I just want a date some time in the past. 585 | */ 586 | var PASTIME = new Date(Math.floor((Date.now() - 31337) / 1000) * 1000); 587 | 588 | namespace.run(function () { 589 | namespace.set('test', 'utimes'); 590 | t.equal(namespace.get('test'), 'utimes', "state has been mutated"); 591 | 592 | var before = fs.statSync(FILENAME); 593 | t.ok(before.atime, "access time of newly-created file set"); 594 | t.ok(before.mtime, "modification time of newly-created file set"); 595 | 596 | fs.utimes(FILENAME, PASTIME, PASTIME, function (error) { 597 | t.notOk(error, "setting utimes shouldn't error"); 598 | 599 | t.equal(namespace.get('test'), 'utimes', 600 | "mutated state has persisted to fs.utimes's callback"); 601 | 602 | var after = fs.statSync(FILENAME); 603 | t.deepEqual(after.atime, PASTIME, "access time of newly-created file is reset"); 604 | t.deepEqual(after.mtime, PASTIME, "mod time of newly-created file is reset"); 605 | t.notDeepEqual(before.atime, after.atime, "access time changed"); 606 | t.notDeepEqual(before.mtime, after.mtime, "mod time changed"); 607 | 608 | deleteFile(); 609 | t.end(); 610 | }); 611 | }); 612 | }); 613 | 614 | t.test("fs.futimes", function (t) { 615 | createFile(t); 616 | 617 | /* futimes(2) takes seconds since the epoch, and Date() deals with 618 | * milliseconds. I just want a date some time in the past. 619 | */ 620 | var PASTIME = new Date(Math.floor((Date.now() - 0xb33fd) / 1000) * 1000); 621 | 622 | namespace.run(function () { 623 | namespace.set('test', 'futimes'); 624 | t.equal(namespace.get('test'), 'futimes', "state has been mutated"); 625 | 626 | var before = fs.statSync(FILENAME); 627 | t.ok(before.atime, "access time of newly-created file set"); 628 | t.ok(before.mtime, "modification time of newly-created file set"); 629 | 630 | var file = fs.openSync(FILENAME, "w+"); 631 | fs.futimes(file, PASTIME, PASTIME, function (error) { 632 | t.notOk(error, "setting futimes shouldn't error"); 633 | fs.closeSync(file); 634 | 635 | t.equal(namespace.get('test'), 'futimes', 636 | "mutated state has persisted to fs.futimes's callback"); 637 | 638 | var after = fs.statSync(FILENAME); 639 | t.deepEqual(after.atime, PASTIME, "access time of newly-created file is reset"); 640 | t.deepEqual(after.mtime, PASTIME, "mod time of newly-created file is reset"); 641 | t.notDeepEqual(before.atime, after.atime, "access time changed"); 642 | t.notDeepEqual(before.mtime, after.mtime, "mod time changed"); 643 | 644 | deleteFile(); 645 | t.end(); 646 | }); 647 | }); 648 | }); 649 | 650 | t.test("fs.fsync", function (t) { 651 | createFile(t); 652 | 653 | namespace.run(function () { 654 | namespace.set('test', 'fsync'); 655 | t.equal(namespace.get('test'), 'fsync', "state has been mutated"); 656 | 657 | var file = fs.openSync(FILENAME, 'w+'); 658 | fs.fsync(file, function (error) { 659 | t.notOk(error, "syncing the file shouldn't error"); 660 | 661 | t.equal(namespace.get('test'), 'fsync', 662 | "mutated state has persisted to fs.fsync's callback"); 663 | 664 | fs.closeSync(file); 665 | deleteFile(); 666 | t.end(); 667 | }); 668 | }); 669 | }); 670 | 671 | t.test("fs.open", function (t) { 672 | createFile(t); 673 | 674 | namespace.run(function () { 675 | namespace.set('test', 'open'); 676 | t.equal(namespace.get('test'), 'open', "state has been mutated"); 677 | 678 | fs.open(FILENAME, 'r', function (error, file) { 679 | t.notOk(error, "opening the file shouldn't error"); 680 | 681 | t.equal(namespace.get('test'), 'open', 682 | "mutated state has persisted to fs.open's callback"); 683 | 684 | 685 | var contents = new Buffer(4); 686 | fs.readSync(file, contents, 0, 4, 0); 687 | t.equal(contents.toString(), 'UHOH', "contents are still available"); 688 | 689 | fs.closeSync(file); 690 | deleteFile(); 691 | t.end(); 692 | }); 693 | }); 694 | }); 695 | 696 | t.test("fs.close", function (t) { 697 | createFile(t); 698 | 699 | namespace.run(function () { 700 | namespace.set('test', 'close'); 701 | t.equal(namespace.get('test'), 'close', "state has been mutated"); 702 | 703 | var file = fs.openSync(FILENAME, 'r'); 704 | fs.close(file, function (error) { 705 | t.notOk(error, "closing the file shouldn't error"); 706 | 707 | t.equal(namespace.get('test'), 'close', 708 | "mutated state has persisted to fs.close's callback"); 709 | 710 | deleteFile(); 711 | t.end(); 712 | }); 713 | }); 714 | }); 715 | 716 | t.test("fs.read", function (t) { 717 | createFile(t); 718 | 719 | namespace.run(function () { 720 | namespace.set('test', 'read'); 721 | t.equal(namespace.get('test'), 'read', "state has been mutated"); 722 | 723 | var file = fs.openSync(FILENAME, 'r') 724 | , contents = new Buffer(4) 725 | ; 726 | fs.read(file, contents, 0, 4, 0, function (error) { 727 | t.notOk(error, "reading from the file shouldn't error"); 728 | 729 | t.equal(namespace.get('test'), 'read', 730 | "mutated state has persisted to fs.read's callback"); 731 | 732 | t.equal(contents.toString(), 'UHOH', "contents are still available"); 733 | 734 | fs.closeSync(file); 735 | deleteFile(); 736 | t.end(); 737 | }); 738 | }); 739 | }); 740 | 741 | t.test("fs.write", function (t) { 742 | createFile(t); 743 | 744 | namespace.run(function () { 745 | namespace.set('test', 'write'); 746 | t.equal(namespace.get('test'), 'write', "state has been mutated"); 747 | 748 | var file = fs.openSync(FILENAME, 'w') 749 | , contents = new Buffer('yeap') 750 | ; 751 | fs.write(file, contents, 0, 4, 0, function (error) { 752 | t.notOk(error, "writing to the file shouldn't error"); 753 | 754 | t.equal(namespace.get('test'), 'write', 755 | "mutated state has persisted to fs.write's callback"); 756 | 757 | fs.closeSync(file); 758 | 759 | var readback = fs.readFileSync(FILENAME); 760 | t.equal(readback.toString(), 'yeap', "contents are still available"); 761 | 762 | deleteFile(); 763 | t.end(); 764 | }); 765 | }); 766 | }); 767 | 768 | t.test("fs.readFile", function (t) { 769 | createFile(t); 770 | 771 | namespace.run(function () { 772 | namespace.set('test', 'readFile'); 773 | t.equal(namespace.get('test'), 'readFile', "state has been mutated"); 774 | 775 | fs.readFile(FILENAME, function (error, contents) { 776 | t.notOk(error, "reading from the file shouldn't error"); 777 | 778 | t.equal(namespace.get('test'), 'readFile', 779 | "mutated state has persisted to fs.readFile's callback"); 780 | 781 | t.equal(contents.toString(), 'UHOH', "contents are still available"); 782 | 783 | deleteFile(); 784 | t.end(); 785 | }); 786 | }); 787 | }); 788 | 789 | t.test("fs.writeFile", function (t) { 790 | createFile(t); 791 | 792 | namespace.run(function () { 793 | namespace.set('test', 'writeFile'); 794 | t.equal(namespace.get('test'), 'writeFile', "state has been mutated"); 795 | 796 | fs.writeFile(FILENAME, 'woopwoop', function (error) { 797 | t.notOk(error, "rewriting the file shouldn't error"); 798 | 799 | t.equal(namespace.get('test'), 'writeFile', 800 | "mutated state has persisted to fs.writeFile's callback"); 801 | 802 | var readback = fs.readFileSync(FILENAME); 803 | t.equal(readback.toString(), 'woopwoop', "rewritten contents are available"); 804 | 805 | deleteFile(); 806 | t.end(); 807 | }); 808 | }); 809 | }); 810 | 811 | t.test("fs.appendFile", function (t) { 812 | createFile(t); 813 | 814 | namespace.run(function () { 815 | namespace.set('test', 'appendFile'); 816 | t.equal(namespace.get('test'), 'appendFile', "state has been mutated"); 817 | 818 | fs.appendFile(FILENAME, '/jk', function (error) { 819 | t.notOk(error, "appending to the file shouldn't error"); 820 | 821 | t.equal(namespace.get('test'), 'appendFile', 822 | "mutated state has persisted to fs.appendFile's callback"); 823 | 824 | var readback = fs.readFileSync(FILENAME); 825 | t.equal(readback.toString(), 'UHOH/jk', 826 | "appended contents are still available"); 827 | 828 | deleteFile(); 829 | t.end(); 830 | }); 831 | }); 832 | }); 833 | 834 | t.test("fs.exists", function (t) { 835 | createFile(t); 836 | 837 | namespace.run(function () { 838 | namespace.set('test', 'exists'); 839 | t.equal(namespace.get('test'), 'exists', "state has been mutated"); 840 | 841 | fs.exists(FILENAME, function (yep) { 842 | t.equal(namespace.get('test'), 'exists', 843 | "mutated state has persisted to fs.exists's callback"); 844 | 845 | t.ok(yep, "precreated file does indeed exist."); 846 | 847 | fs.exists('NOPENOWAY', function (nope) { 848 | t.equal(namespace.get('test'), 'exists', 849 | "mutated state continues to persist to fs.exists's second callback"); 850 | 851 | t.notOk(nope, "nonexistent file doesn't exist."); 852 | 853 | deleteFile(); 854 | t.end(); 855 | }); 856 | }); 857 | }); 858 | }); 859 | 860 | t.test("fs.watchFile", function (t) { 861 | createFile(t); 862 | 863 | namespace.run(function () { 864 | namespace.set('test', 'watchFile'); 865 | t.equal(namespace.get('test'), 'watchFile', "state has been mutated"); 866 | 867 | var options = { 868 | persistent: true, 869 | interval: 20 870 | }; 871 | 872 | fs.watchFile(FILENAME, options, function (before, after) { 873 | t.equal(namespace.get('test'), 'watchFile', 874 | "mutated state has persisted to fs.watchFile's callback"); 875 | 876 | t.ok(before.ino, "file has an entry"); 877 | t.equal(before.ino, after.ino, "file is at the same location"); 878 | 879 | fs.unwatchFile(FILENAME); 880 | process.nextTick(function () { 881 | deleteFile(); 882 | t.end(); 883 | }); 884 | }); 885 | 886 | setTimeout(function poke() { 887 | fs.appendFileSync(FILENAME, 'still a test'); 888 | }, 20); 889 | }); 890 | }); 891 | }); 892 | }); 893 | -------------------------------------------------------------------------------- /test/interleave-contexts.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var cls = require('../context.js') 4 | , test = require('tap').test 5 | ; 6 | 7 | function cleanNamespace(name){ 8 | if (cls.getNamespace(name)) cls.destroyNamespace(name); 9 | return cls.createNamespace(name); 10 | } 11 | 12 | test("interleaved contexts", function (t) { 13 | t.plan(3); 14 | 15 | t.test("interleaving with run", function (t) { 16 | t.plan(2); 17 | 18 | var ns = cleanNamespace('test'); 19 | 20 | var ctx = ns.createContext(); 21 | 22 | ns.enter(ctx); 23 | ns.run(function () { 24 | t.equal(ns._set.length, 2, "2 contexts in the active set"); 25 | t.doesNotThrow(function () { ns.exit(ctx); }); 26 | }); 27 | }); 28 | 29 | t.test("entering and exiting staggered", function (t) { 30 | t.plan(4); 31 | 32 | var ns = cleanNamespace('test'); 33 | 34 | var ctx1 = ns.createContext(); 35 | var ctx2 = ns.createContext(); 36 | 37 | t.doesNotThrow(function () { ns.enter(ctx1); }); 38 | t.doesNotThrow(function () { ns.enter(ctx2); }); 39 | 40 | t.doesNotThrow(function () { ns.exit(ctx1); }); 41 | t.doesNotThrow(function () { ns.exit(ctx2); }); 42 | }); 43 | 44 | t.test("creating, entering and exiting staggered", function (t) { 45 | t.plan(4); 46 | 47 | var ns = cleanNamespace('test'); 48 | 49 | var ctx1 = ns.createContext(); 50 | t.doesNotThrow(function () { ns.enter(ctx1); }); 51 | 52 | var ctx2 = ns.createContext(); 53 | t.doesNotThrow(function () { ns.enter(ctx2); }); 54 | 55 | t.doesNotThrow(function () { ns.exit(ctx1); }); 56 | t.doesNotThrow(function () { ns.exit(ctx2); }); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /test/monkeypatching.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var test = require('tap').test; 3 | 4 | if (!process.addAsyncListener) { 5 | test("overwriting startup.processNextTick", function (t) { 6 | t.plan(2); 7 | 8 | t.doesNotThrow(function () { require('../context.js'); }); 9 | 10 | t.ok(process.nextTick.__wrapped, "should wrap process.nextTick()"); 11 | }); 12 | 13 | test("overwriting domain helpers", function (t) { 14 | // domain helpers were only in 0.10.x 15 | if (!(process._nextDomainTick && process._tickDomainCallback)) { 16 | return t.end(); 17 | } 18 | 19 | t.plan(2); 20 | 21 | t.ok(process._nextDomainTick.__wrapped, 22 | "should wrap process._nextDomainTick()"); 23 | t.ok(process._tickDomainCallback.__wrapped, 24 | "should wrap process._tickDomainCallback()"); 25 | }); 26 | 27 | test("overwriting timers", function (t) { 28 | t.plan(2); 29 | 30 | var timers = require('timers'); 31 | t.ok(timers.setTimeout.__wrapped, "should wrap setTimeout()"); 32 | t.ok(timers.setInterval.__wrapped, "should wrap setInterval()"); 33 | 34 | /* It would be nice to test that monkeypatching preserves the status quo 35 | * ante, but assert thinks setTimeout !== global.setTimeout (why?) and both of 36 | * those are a wrapper around NativeModule.require("timers").setTimeout, 37 | * presumably to try to prevent the kind of "fun" I'm having here. 38 | */ 39 | }); 40 | 41 | test("overwriting setImmediate", function (t) { 42 | // setTimeout's a johnny-come-lately 43 | if (!global.setImmediate) return t.end(); 44 | 45 | t.plan(1); 46 | 47 | t.ok(require('timers').setImmediate.__wrapped, "should wrap setImmediate()"); 48 | 49 | /* It would be nice to test that monkeypatching preserves the status quo 50 | * ante, but assert thinks setTimeout !== global.setTimeout (why?) and both of 51 | * those are a wrapper around NativeModule.require("timers").setTimeout, 52 | * presumably to try to prevent the kind of "fun" I'm having here. 53 | */ 54 | }); 55 | } 56 | -------------------------------------------------------------------------------- /test/namespaces.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var tap = require('tap'); 4 | var test = tap.test; 5 | 6 | var context = require('../context.js'); 7 | 8 | test("namespace management", function (t) { 9 | t.plan(8); 10 | 11 | t.throws(function () { context.createNamespace(); }, "name is required"); 12 | 13 | var namespace = context.createNamespace('test'); 14 | t.ok(namespace, "namespace is returned upon creation"); 15 | 16 | t.equal(context.getNamespace('test'), namespace, "namespace lookup works"); 17 | 18 | t.doesNotThrow(function () { context.reset(); }, "allows resetting namespaces"); 19 | 20 | t.equal(Object.keys(process.namespaces).length, 0, "namespaces have been reset"); 21 | 22 | namespace = context.createNamespace('another'); 23 | t.ok(process.namespaces.another, "namespace is available from global"); 24 | 25 | t.doesNotThrow(function () { context.destroyNamespace('another'); }, 26 | "destroying works"); 27 | 28 | t.notOk(process.namespaces.another, "namespace has been removed"); 29 | }); 30 | -------------------------------------------------------------------------------- /test/nesting.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var tap = require('tap'); 4 | var test = tap.test; 5 | 6 | var cls = require('../context.js'); 7 | 8 | test("nested contexts on a single namespace", function (t) { 9 | t.plan(7); 10 | 11 | var namespace = cls.createNamespace("namespace"); 12 | namespace.run(function () { 13 | namespace.set("value", 1); 14 | 15 | t.equal(namespace.get("value"), 1, 16 | "namespaces have associated data even without contexts."); 17 | 18 | namespace.run(function () { 19 | t.equal(namespace.get("value"), 1, "lookup will check enclosing context"); 20 | namespace.set("value", 2); 21 | t.equal(namespace.get("value"), 2, "setting works on top-level context"); 22 | 23 | namespace.run(function () { 24 | t.equal(namespace.get("value"), 2, "lookup will check enclosing context"); 25 | namespace.set("value", 3); 26 | t.equal(namespace.get("value"), 3, "setting works on nested context"); 27 | }); 28 | 29 | t.equal(namespace.get("value"), 2, 30 | "should revert to value set in top-level context"); 31 | }); 32 | 33 | t.equal(namespace.get("value"), 1, "namespace retains its outermost value."); 34 | }); 35 | }); 36 | 37 | test("the example from the docs", function (t) { 38 | var writer = cls.createNamespace('writer'); 39 | writer.run(function () { 40 | writer.set('value', 0); 41 | 42 | t.equal(writer.get('value'), 0, "outer hasn't been entered yet"); 43 | function requestHandler() { 44 | writer.run(function (outer) { 45 | t.equal(writer.active, outer, "writer.active == outer"); 46 | 47 | writer.set('value', 1); 48 | t.equal(writer.get('value'), 1, "writer.active == outer"); 49 | t.equal(outer.value, 1, "outer is active"); 50 | 51 | process.nextTick(function () { 52 | t.equal(writer.active, outer, "writer.active == outer"); 53 | t.equal(writer.get('value'), 1, "inner has been entered"); 54 | writer.run(function (inner) { 55 | t.equal(writer.active, inner, "writer.active == inner"); 56 | 57 | writer.set('value', 2); 58 | t.equal(outer.value, 1, "outer is unchanged"); 59 | t.equal(inner.value, 2, "inner is active"); 60 | t.equal(writer.get('value'), 2, "writer.active == inner"); 61 | }); 62 | }); 63 | }); 64 | 65 | setTimeout(function () { 66 | t.equal(writer.get('value'), 0, "writer.active == global"); 67 | t.end(); 68 | }, 100); 69 | } 70 | 71 | requestHandler(); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /test/net-events.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var net = require('net') 4 | , tap = require('tap') 5 | , test = tap.test 6 | , createNamespace = require('../context').createNamespace 7 | ; 8 | 9 | test("continuation-local state with net connection", function (t) { 10 | t.plan(4); 11 | 12 | var namespace = createNamespace('net'); 13 | namespace.run(function () { 14 | namespace.set('test', 0xabad1dea); 15 | 16 | var server; 17 | namespace.run(function () { 18 | namespace.set('test', 0x1337); 19 | 20 | server = net.createServer(function (socket) { 21 | t.equal(namespace.get('test'), 0x1337, "state has been mutated"); 22 | socket.on("data", function () { 23 | t.equal(namespace.get('test'), 0x1337, "state is still preserved"); 24 | server.close(); 25 | socket.end("GoodBye"); 26 | }); 27 | }); 28 | server.listen(function () { 29 | var address = server.address(); 30 | namespace.run(function () { 31 | namespace.set("test", "MONKEY"); 32 | var client = net.connect(address.port, function () { 33 | t.equal(namespace.get("test"), "MONKEY", 34 | "state preserved for client connection"); 35 | client.write("Hello"); 36 | client.on("data", function () { 37 | t.equal(namespace.get("test"), "MONKEY", "state preserved for client data"); 38 | t.end(); 39 | }); 40 | }); 41 | }); 42 | }); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /test/promises.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var tap = require('tap') 4 | , test = tap.test 5 | , createNamespace = require('../context.js').createNamespace 6 | ; 7 | 8 | test("continuation-local state with promises", function (t) { 9 | t.plan(4); 10 | 11 | var namespace = createNamespace('namespace'); 12 | namespace.run(function () { 13 | namespace.set('test', 0xabad1dea); 14 | 15 | t.test("chained promises", function (t) { 16 | if (!global.Promise) return t.end(); 17 | 18 | namespace.run(function () { 19 | namespace.set('test', 31337); 20 | t.equal(namespace.get('test'), 31337, "state has been mutated"); 21 | 22 | Promise.resolve() 23 | .then(function () { 24 | t.equal(namespace.get('test'), 31337, 25 | "mutated state has persisted to first continuation"); 26 | }) 27 | .then(function () { 28 | t.equal(namespace.get('test'), 31337, 29 | "mutated state has persisted to second continuation"); 30 | }) 31 | .then(function () { 32 | t.equal(namespace.get('test'), 31337, 33 | "mutated state has persisted to third continuation"); 34 | t.end(); 35 | }); 36 | }); 37 | }); 38 | 39 | t.test("chained unwrapped promises", function (t) { 40 | if (!global.Promise) return t.end(); 41 | 42 | namespace.run(function () { 43 | namespace.set('test', 999); 44 | t.equal(namespace.get('test'), 999, "state has been mutated"); 45 | 46 | Promise.resolve() 47 | .then(function () { 48 | t.equal(namespace.get('test'), 999, 49 | "mutated state has persisted to first continuation"); 50 | return Promise.resolve(); 51 | }) 52 | .then(function () { 53 | t.equal(namespace.get('test'), 999, 54 | "mutated state has persisted to second continuation"); 55 | return Promise.resolve(); 56 | }) 57 | .then(function () { 58 | t.equal(namespace.get('test'), 999, 59 | "mutated state has persisted to third continuation"); 60 | t.end(); 61 | }); 62 | }); 63 | }); 64 | 65 | t.test("nested promises", function (t) { 66 | if (!global.Promise) return t.end(); 67 | 68 | namespace.run(function () { 69 | namespace.set('test', 54321); 70 | t.equal(namespace.get('test'), 54321, "state has been mutated"); 71 | 72 | Promise.resolve() 73 | .then(function () { 74 | t.equal(namespace.get('test'), 54321, 75 | "mutated state has persisted to first continuation"); 76 | 77 | Promise.resolve() 78 | .then(function () { 79 | t.equal(namespace.get('test'), 54321, 80 | "mutated state has persisted to second continuation"); 81 | 82 | Promise.resolve() 83 | .then(function () { 84 | t.equal(namespace.get('test'), 54321, 85 | "mutated state has persisted to third continuation"); 86 | t.end(); 87 | }); 88 | }); 89 | }); 90 | }); 91 | }); 92 | 93 | t.test("forked continuations", function (t) { 94 | if (!global.Promise) return t.end(); 95 | 96 | namespace.run(function () { 97 | namespace.set('test', 10101); 98 | t.equal(namespace.get('test'), 10101, "state has been mutated"); 99 | 100 | var promise = Promise.resolve(); 101 | 102 | promise 103 | .then(function () { 104 | t.equal(namespace.get('test'), 10101, 105 | "mutated state has persisted to first continuation"); 106 | }); 107 | promise 108 | .then(function () { 109 | t.equal(namespace.get('test'), 10101, 110 | "mutated state has persisted to second continuation"); 111 | }); 112 | promise 113 | .then(function () { 114 | t.equal(namespace.get('test'), 10101, 115 | "mutated state has persisted to third continuation"); 116 | t.end(); 117 | }); 118 | }); 119 | }); 120 | }); 121 | }); 122 | -------------------------------------------------------------------------------- /test/proper-exit.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // I love when a tap.plan() comes together 4 | console.log('1..1'); 5 | 6 | process.on('uncaughtException', function (err) { 7 | if (err.message === 'oops') { 8 | console.log("ok got expected message: %s", err.message); 9 | } 10 | else { 11 | throw err; 12 | } 13 | }); 14 | 15 | var cls = require('../context.js'); 16 | var ns = cls.createNamespace('x'); 17 | ns.run(function () { throw new Error('oops'); }); 18 | -------------------------------------------------------------------------------- /test/run-and-return.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // stdlib 4 | var tap = require('tap'); 5 | var test = tap.test; 6 | var EventEmitter = require('events').EventEmitter; 7 | 8 | // module under test 9 | var context = require('../context.js'); 10 | 11 | // multiple contexts in use 12 | var tracer = context.createNamespace('tracer'); 13 | 14 | 15 | test("simple tracer built on contexts", function (t) { 16 | t.plan(7); 17 | 18 | var harvester = new EventEmitter(); 19 | 20 | harvester.on('finished', function (transaction) { 21 | t.ok(transaction, "transaction should have been passed in"); 22 | t.equal(transaction.status, 'ok', "transaction should have finished OK"); 23 | t.equal(Object.keys(process.namespaces).length, 1, "Should only have one namespace."); 24 | }); 25 | 26 | var returnValue = {}; 27 | 28 | var returnedValue = tracer.runAndReturn(function(context) { 29 | t.ok(tracer.active, "tracer should have an active context"); 30 | tracer.set('transaction', {status : 'ok'}); 31 | t.ok(tracer.get('transaction'), "can retrieve newly-set value"); 32 | t.equal(tracer.get('transaction').status, 'ok', "value should be correct"); 33 | 34 | harvester.emit('finished', context.transaction); 35 | 36 | return returnValue; 37 | }); 38 | 39 | t.equal(returnedValue, returnValue, "method should pass through return value of function run in scope"); 40 | }); 41 | -------------------------------------------------------------------------------- /test/simple.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // stdlib 4 | var tap = require('tap'); 5 | var test = tap.test; 6 | var EventEmitter = require('events').EventEmitter; 7 | 8 | // module under test 9 | var context = require('../context.js'); 10 | 11 | // multiple contexts in use 12 | var tracer = context.createNamespace('tracer'); 13 | 14 | function Trace(harvester) { 15 | this.harvester = harvester; 16 | } 17 | 18 | Trace.prototype.runHandler = function (handler) { 19 | var trace = tracer.run(handler); 20 | this.harvester.emit('finished', trace.transaction); 21 | }; 22 | 23 | 24 | test("simple tracer built on contexts", function (t) { 25 | t.plan(6); 26 | 27 | var harvester = new EventEmitter(); 28 | var trace = new Trace(harvester); 29 | 30 | harvester.on('finished', function (transaction) { 31 | t.ok(transaction, "transaction should have been passed in"); 32 | t.equal(transaction.status, 'ok', "transaction should have finished OK"); 33 | t.equal(Object.keys(process.namespaces).length, 1, "Should only have one namespace."); 34 | }); 35 | 36 | trace.runHandler(function inScope() { 37 | t.ok(tracer.active, "tracer should have an active context"); 38 | tracer.set('transaction', {status : 'ok'}); 39 | t.ok(tracer.get('transaction'), "can retrieve newly-set value"); 40 | t.equal(tracer.get('transaction').status, 'ok', "value should be correct"); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/timers.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var tap = require('tap') 4 | , test = tap.test 5 | , createNamespace = require('../context.js').createNamespace 6 | ; 7 | 8 | test("continuation-local state with timers", function (t) { 9 | t.plan(4); 10 | 11 | var namespace = createNamespace('namespace'); 12 | namespace.run(function () { 13 | namespace.set('test', 0xabad1dea); 14 | 15 | t.test("process.nextTick", function (t) { 16 | namespace.run(function () { 17 | namespace.set('test', 31337); 18 | t.equal(namespace.get('test'), 31337, "state has been mutated"); 19 | 20 | process.nextTick(function () { 21 | t.equal(namespace.get('test'), 31337, 22 | "mutated state has persisted to process.nextTick's callback"); 23 | 24 | t.end(); 25 | }); 26 | }); 27 | }); 28 | 29 | t.test("setImmediate", function (t) { 30 | // setImmediate only in Node > 0.9.x 31 | if (!global.setImmediate) return t.end(); 32 | 33 | namespace.run(function () { 34 | namespace.set('test', 999); 35 | t.equal(namespace.get('test'), 999, "state has been mutated"); 36 | 37 | setImmediate(function () { 38 | t.equal(namespace.get('test'), 999, 39 | "mutated state has persisted to setImmediate's callback"); 40 | 41 | t.end(); 42 | }); 43 | }); 44 | }); 45 | 46 | t.test("setTimeout", function (t) { 47 | namespace.run(function () { 48 | namespace.set('test', 54321); 49 | t.equal(namespace.get('test'), 54321, "state has been mutated"); 50 | 51 | setTimeout(function () { 52 | t.equal(namespace.get('test'), 54321, 53 | "mutated state has persisted to setTimeout's callback"); 54 | 55 | t.end(); 56 | }); 57 | }); 58 | }); 59 | 60 | t.test("setInterval", function (t) { 61 | namespace.run(function () { 62 | namespace.set('test', 10101); 63 | t.equal(namespace.get('test'), 10101, 64 | "continuation-local state has been mutated"); 65 | 66 | var ref = setInterval(function () { 67 | t.equal(namespace.get('test'), 10101, 68 | "mutated state has persisted to setInterval's callback"); 69 | 70 | clearInterval(ref); 71 | t.end(); 72 | }, 20); 73 | }); 74 | }); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /test/tracer-scenarios.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var EventEmitter = require('events').EventEmitter 4 | , assert = require('assert') 5 | , test = require('tap').test 6 | , cls = require('../context.js') 7 | ; 8 | 9 | var nextID = 1; 10 | function fresh(name) { 11 | assert.ok(!cls.getNamespace(name), "namespace " + name + " already exists"); 12 | return cls.createNamespace(name); 13 | } 14 | 15 | function destroy(name) { 16 | return function destroyer(t) { 17 | cls.destroyNamespace(name); 18 | assert.ok(!cls.getNamespace(name), "namespace '" + name + "' should no longer exist"); 19 | t.end(); 20 | }; 21 | } 22 | 23 | function runInTransaction(name, fn) { 24 | var namespace = cls.getNamespace(name); 25 | assert(namespace, "namespaces " + name + " doesn't exist"); 26 | 27 | var context = namespace.createContext(); 28 | context.transaction = ++nextID; 29 | process.nextTick(namespace.bind(fn, context)); 30 | } 31 | 32 | test("asynchronous state propagation", function (t) { 33 | t.plan(24); 34 | 35 | t.test("a. async transaction with setTimeout", function (t) { 36 | t.plan(2); 37 | 38 | var namespace = fresh('a', this); 39 | 40 | function handler() { 41 | t.ok(namespace.get('transaction'), "transaction should be visible"); 42 | } 43 | 44 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 45 | runInTransaction('a', function () { setTimeout(handler, 100); }); 46 | }); 47 | 48 | t.test("a. cleanup", destroy('a')); 49 | 50 | t.test("b. async transaction with setInterval", function (t) { 51 | t.plan(4); 52 | 53 | var namespace = fresh('b', this) 54 | , count = 0 55 | , handle 56 | ; 57 | 58 | function handler() { 59 | count += 1; 60 | if (count > 2) clearInterval(handle); 61 | t.ok(namespace.get('transaction'), "transaction should be visible"); 62 | } 63 | 64 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 65 | runInTransaction('b', function () { handle = setInterval(handler, 50); }); 66 | }); 67 | 68 | t.test("b. cleanup", destroy('b')); 69 | 70 | t.test("c. async transaction with process.nextTick", function (t) { 71 | t.plan(2); 72 | 73 | var namespace = fresh('c', this); 74 | 75 | function handler() { 76 | t.ok(namespace.get('transaction'), "transaction should be visible"); 77 | } 78 | 79 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 80 | runInTransaction('c', function () { process.nextTick(handler); }); 81 | }); 82 | 83 | t.test("c. cleanup", destroy('c')); 84 | 85 | t.test("d. async transaction with EventEmitter.emit", function (t) { 86 | t.plan(2); 87 | 88 | var namespace = fresh('d', this) 89 | , ee = new EventEmitter() 90 | ; 91 | 92 | function handler() { 93 | t.ok(namespace.get('transaction'), "transaction should be visible"); 94 | } 95 | 96 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 97 | runInTransaction('d', function () { 98 | ee.on('transaction', handler); 99 | ee.emit('transaction'); 100 | }); 101 | }); 102 | 103 | t.test("d. cleanup", destroy('d')); 104 | 105 | t.test("e. two overlapping async transactions with setTimeout", function (t) { 106 | t.plan(6); 107 | 108 | var namespace = fresh('e', this) 109 | , first 110 | , second 111 | ; 112 | 113 | function handler(id) { 114 | t.ok(namespace.get('transaction'), "transaction should be visible"); 115 | t.equal(namespace.get('transaction'), id, "transaction matches"); 116 | } 117 | 118 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 119 | runInTransaction('e', function () { 120 | first = namespace.get('transaction'); 121 | setTimeout(handler.bind(null, first), 100); 122 | }); 123 | 124 | setTimeout(function () { 125 | runInTransaction('e', function () { 126 | second = namespace.get('transaction'); 127 | t.notEqual(first, second, "different transaction IDs"); 128 | setTimeout(handler.bind(null, second), 100); 129 | }); 130 | }, 25); 131 | }); 132 | 133 | t.test("e. cleanup", destroy('e')); 134 | 135 | t.test("f. two overlapping async transactions with setInterval", function (t) { 136 | t.plan(15); 137 | 138 | var namespace = fresh('f', this); 139 | 140 | function runInterval() { 141 | var count = 0 142 | , handle 143 | , id 144 | ; 145 | 146 | function handler() { 147 | count += 1; 148 | if (count > 2) clearInterval(handle); 149 | t.ok(namespace.get('transaction'), "transaction should be visible"); 150 | t.equal(id, namespace.get('transaction'), "transaction ID should be immutable"); 151 | } 152 | 153 | function run() { 154 | t.ok(namespace.get('transaction'), "transaction should have been created"); 155 | id = namespace.get('transaction'); 156 | handle = setInterval(handler, 50); 157 | } 158 | 159 | runInTransaction('f', run); 160 | } 161 | 162 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 163 | runInterval(); runInterval(); 164 | }); 165 | 166 | t.test("f. cleanup", destroy('f')); 167 | 168 | t.test("g. two overlapping async transactions with process.nextTick", function (t) { 169 | t.plan(6); 170 | 171 | var namespace = fresh('g', this) 172 | , first 173 | , second 174 | ; 175 | 176 | function handler(id) { 177 | var transaction = namespace.get('transaction'); 178 | t.ok(transaction, "transaction should be visible"); 179 | t.equal(transaction, id, "transaction matches"); 180 | } 181 | 182 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 183 | runInTransaction('g', function () { 184 | first = namespace.get('transaction'); 185 | process.nextTick(handler.bind(null, first)); 186 | }); 187 | 188 | process.nextTick(function () { 189 | runInTransaction('g', function () { 190 | second = namespace.get('transaction'); 191 | t.notEqual(first, second, "different transaction IDs"); 192 | process.nextTick(handler.bind(null, second)); 193 | }); 194 | }); 195 | }); 196 | 197 | t.test("g. cleanup", destroy('g')); 198 | 199 | t.test("h. two overlapping async runs with EventEmitter.prototype.emit", function (t) { 200 | t.plan(3); 201 | 202 | var namespace = fresh('h', this) 203 | , ee = new EventEmitter() 204 | ; 205 | 206 | function handler() { 207 | t.ok(namespace.get('transaction'), "transaction should be visible"); 208 | } 209 | 210 | function lifecycle() { 211 | ee.once('transaction', process.nextTick.bind(process, handler)); 212 | ee.emit('transaction'); 213 | } 214 | 215 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 216 | runInTransaction('h', lifecycle); 217 | runInTransaction('h', lifecycle); 218 | }); 219 | 220 | t.test("h. cleanup", destroy('h')); 221 | 222 | t.test("i. async transaction with an async sub-call with setTimeout", function (t) { 223 | t.plan(5); 224 | 225 | var namespace = fresh('i', this); 226 | 227 | function inner(callback) { 228 | setTimeout(function () { 229 | t.ok(namespace.get('transaction'), "transaction should (yep) still be visible"); 230 | callback(); 231 | }, 50); 232 | } 233 | 234 | function outer() { 235 | t.ok(namespace.get('transaction'), "transaction should be visible"); 236 | setTimeout(function () { 237 | t.ok(namespace.get('transaction'), "transaction should still be visible"); 238 | inner(function () { 239 | t.ok(namespace.get('transaction'), "transaction should even still be visible"); 240 | }); 241 | }, 50); 242 | } 243 | 244 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 245 | runInTransaction('i', setTimeout.bind(null, outer, 50)); 246 | }); 247 | 248 | t.test("i. cleanup", destroy('i')); 249 | 250 | t.test("j. async transaction with an async sub-call with setInterval", function (t) { 251 | t.plan(5); 252 | 253 | var namespace = fresh('j', this) 254 | , outerHandle 255 | , innerHandle 256 | ; 257 | 258 | function inner(callback) { 259 | innerHandle = setInterval(function () { 260 | clearInterval(innerHandle); 261 | t.ok(namespace.get('transaction'), "transaction should (yep) still be visible"); 262 | callback(); 263 | }, 50); 264 | } 265 | 266 | function outer() { 267 | t.ok(namespace.get('transaction'), "transaction should be visible"); 268 | outerHandle = setInterval(function () { 269 | clearInterval(outerHandle); 270 | t.ok(namespace.get('transaction'), "transaction should still be visible"); 271 | inner(function () { 272 | t.ok(namespace.get('transaction'), "transaction should even still be visible"); 273 | }); 274 | }, 50); 275 | } 276 | 277 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 278 | runInTransaction('j', outer); 279 | }); 280 | 281 | t.test("j. cleanup", destroy('j')); 282 | 283 | t.test("k. async transaction with an async call with process.nextTick", function (t) { 284 | t.plan(5); 285 | 286 | var namespace = fresh('k', this); 287 | 288 | function inner(callback) { 289 | process.nextTick(function () { 290 | t.ok(namespace.get('transaction'), "transaction should (yep) still be visible"); 291 | callback(); 292 | }); 293 | } 294 | 295 | function outer() { 296 | t.ok(namespace.get('transaction'), "transaction should be visible"); 297 | process.nextTick(function () { 298 | t.ok(namespace.get('transaction'), "transaction should still be visible"); 299 | inner(function () { 300 | t.ok(namespace.get('transaction'), "transaction should even still be visible"); 301 | }); 302 | }); 303 | } 304 | 305 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 306 | runInTransaction('k', function () { process.nextTick(outer); }); 307 | }); 308 | 309 | t.test("k. cleanup", destroy('k')); 310 | 311 | t.test("l. async transaction with an async call with EventEmitter.emit", function (t) { 312 | t.plan(4); 313 | 314 | var namespace = fresh('l', this) 315 | , outer = new EventEmitter() 316 | , inner = new EventEmitter() 317 | ; 318 | 319 | inner.on('pong', function (callback) { 320 | t.ok(namespace.get('transaction'), "transaction should still be visible"); 321 | callback(); 322 | }); 323 | 324 | function outerCallback() { 325 | t.ok(namespace.get('transaction'), "transaction should even still be visible"); 326 | } 327 | 328 | outer.on('ping', function () { 329 | t.ok(namespace.get('transaction'), "transaction should be visible"); 330 | inner.emit('pong', outerCallback); 331 | }); 332 | 333 | t.notOk(namespace.get('transaction'), "transaction should not yet be visible"); 334 | runInTransaction('l', outer.emit.bind(outer, 'ping')); 335 | }); 336 | 337 | t.test("l. cleanup", destroy('l')); 338 | }); 339 | -------------------------------------------------------------------------------- /test/zlib.tap.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var tap = require('tap') 4 | , test = tap.test 5 | , createNamespace = require('../context.js').createNamespace 6 | ; 7 | 8 | var zlib = require('zlib'); 9 | 10 | test("continuation-local state with zlib", function (t) { 11 | t.plan(1); 12 | 13 | var namespace = createNamespace('namespace'); 14 | namespace.run(function () { 15 | namespace.set('test', 0xabad1dea); 16 | 17 | t.test("deflate", function (t) { 18 | namespace.run(function () { 19 | namespace.set('test', 42); 20 | zlib.deflate(new Buffer("Goodbye World"), function (err) { 21 | if (err) throw err; 22 | t.equal(namespace.get('test'), 42, "mutated state was preserved"); 23 | t.end(); 24 | }); 25 | }); 26 | }); 27 | }); 28 | }); 29 | --------------------------------------------------------------------------------