Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

continuation-local-storage

Package Overview
Dependencies
Maintainers
1
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

continuation-local-storage - npm Package Compare versions

Comparing version 2.4.4 to 2.5.0

test/interleave-contexts.tap.js

128

context.js

@@ -6,2 +6,9 @@ 'use strict';

/*
*
* CONSTANTS
*
*/
var CONTEXTS_SYMBOL = 'cls@contexts';
// load polyfill if native support is unavailable

@@ -16,3 +23,3 @@ if (!process.addAsyncListener) require('async-listener');

this.active = Object.create(null);
this._stack = [];
this._set = [];
this.id = null;

@@ -63,3 +70,3 @@ }

this._stack.push(this.active);
this._set.push(this.active);
this.active = context;

@@ -73,4 +80,4 @@ };

if (this.active === context) {
assert.ok(this._stack.length, "can't remove top context");
this.active = this._stack.pop();
assert.ok(this._set.length, "can't remove top context");
this.active = this._set.pop();
return;

@@ -80,3 +87,3 @@ }

// Fast search in the stack using lastIndexOf
var index = this._stack.lastIndexOf(context);
var index = this._set.lastIndexOf(context);

@@ -86,95 +93,36 @@ assert.ok(index >= 0, "context not currently entered; can't exit");

this.active = this._stack[index - 1];
this._stack.length = index - 1;
this._set.splice(index, 1);
};
Namespace.prototype.bindEmitter = function (source) {
assert.ok(source.on && source.addListener && source.emit, "can only bind real EEs");
Namespace.prototype.bindEmitter = function (emitter) {
assert.ok(emitter.on && emitter.addListener && emitter.emit, "can only bind real EEs");
var namespace = this;
var contextName = 'context@' + this.name;
var namespace = this;
var thisSymbol = 'context@' + this.name;
/**
* Attach a context to a listener, and make sure that this hook stays
* attached to the emitter forevermore.
*/
function capturer(on) {
return function captured(event, listener) {
listener[contextName] = namespace.active;
try {
return on.call(this, event, listener);
}
finally {
// old-style streaming overwrites .on and .addListener, so rewrap
if (!this.on.__wrapped) shimmer.wrap(this, 'on', capturer);
if (!this.addListener.__wrapped) shimmer.wrap(this, 'addListener', capturer);
}
// Capture the context active at the time the emitter is bound.
function attach(listener) {
if (!listener) return;
if (!listener[CONTEXTS_SYMBOL]) listener[CONTEXTS_SYMBOL] = Object.create(null);
listener[CONTEXTS_SYMBOL][thisSymbol] = {
namespace : namespace,
context : namespace.active
};
}
/**
* Evaluate listeners within the CLS contexts in which they were originally
* captured.
*/
function puncher(emit) {
// find all the handlers with attached contexts
function prepare(unwrapped) {
if (!unwrapped) return;
// At emit time, bind the listener within the correct context.
function bind(unwrapped) {
if (!(unwrapped && unwrapped[CONTEXTS_SYMBOL])) return unwrapped;
if (typeof unwrapped === 'function' && unwrapped[contextName]) {
return namespace.bind(unwrapped, unwrapped[contextName]);
}
else if (Array.isArray(unwrapped) && unwrapped.length) {
var replacements = [];
for (var i = 0; i < unwrapped.length; i++) {
var handler = unwrapped[i];
var context = handler[contextName];
if (context) handler = namespace.bind(handler, context);
replacements[i] = handler;
}
return replacements;
}
else {
return unwrapped;
}
}
return function punched(event) {
if (!this._events || !this._events[event]) return emit.apply(this, arguments);
// wrap
var unwrapped = this._events[event];
function releaser(removeListener) {
return function unwrapRemove() {
this._events[event] = unwrapped;
try {
return removeListener.apply(this, arguments);
}
finally {
unwrapped = this._events[event];
this._events[event] = prepare(unwrapped);
}
};
}
shimmer.wrap(this, 'removeListener', releaser);
this._events[event] = prepare(unwrapped);
try {
// apply
return emit.apply(this, arguments);
}
finally {
// reset
shimmer.unwrap(this, 'removeListener');
this._events[event] = unwrapped;
}
};
var wrapped = unwrapped;
var contexts = unwrapped[CONTEXTS_SYMBOL];
Object.keys(contexts).forEach(function (name) {
var thunk = contexts[name];
wrapped = thunk.namespace.bind(wrapped, thunk.context);
});
return wrapped;
}
shimmer.wrap(source, 'addListener', capturer);
shimmer.wrap(source, 'on', capturer);
shimmer.wrap(source, 'emit', puncher);
shimmer.wrapEmitter(emitter, attach, bind);
};

@@ -191,5 +139,3 @@

namespace.id = process.addAsyncListener(
function () {
return namespace.active;
},
function () { return namespace.active; },
{

@@ -196,0 +142,0 @@ before : function (context, domain) { namespace.enter(domain); },

{
"name": "continuation-local-storage",
"version": "2.4.4",
"version": "2.5.0",
"description": "userland implementation of https://github.com/joyent/node/issues/5243",

@@ -37,4 +37,4 @@ "main": "context.js",

"dependencies": {
"shimmer": "0.7.3"
"shimmer": "~0.9"
}
}

@@ -16,3 +16,3 @@ 'use strict';

test("event emitters bound to CLS context", function (t) {
t.plan(10);
t.plan(12);

@@ -210,3 +210,4 @@ t.test("handler registered in context", function (t) {

t.equal(typeof re._events.data, 'function', 'only the one data listener');
t.ok(re._events.data['context@outOnReadable'], "context is bound to listener");
t.ok(re._events.data['cls@contexts']['context@outOnReadable'],
"context is bound to listener");

@@ -277,3 +278,3 @@ re.emit('data', 'blah');

var ee = new EventEmitter()
, n = fresh('kaboom', this)
, n = fresh('param_list', this)
;

@@ -291,2 +292,60 @@

});
t.test("listener that throws doesn't leave removeListener wrapped", function (t) {
t.plan(4);
var ee = new EventEmitter()
, n = fresh('kaboom', this)
;
n.bindEmitter(ee);
function kaboom() {
throw new Error('whoops');
}
n.run(function () {
ee.on('bad', kaboom);
t.throws(function () { ee.emit('bad'); });
t.equal(typeof ee.removeListener, 'function', 'removeListener is still there');
t.notOk(ee.removeListener.__wrapped, "removeListener got unwrapped");
t.equal(ee._events.bad, kaboom, "listener isn't still bound");
});
});
t.test("emitter bound to multiple namespaces handles them correctly", function (t) {
t.plan(6);
var ee = new EventEmitter()
, ns1 = cls.createNamespace('1')
, ns2 = cls.createNamespace('2')
;
// emulate an incoming data emitter
setTimeout(function () {
ee.emit('data', 'hi');
}, 10);
ns1.set('name', 'tom1');
ns2.set('name', 'tom2');
t.doesNotThrow(function () { ns1.bindEmitter(ee); });
t.doesNotThrow(function () { ns2.bindEmitter(ee); });
ns1.run(function () {
process.nextTick(function () {
t.equal(ns1.get('name'), 'tom1', "ns1 value correct");
t.equal(ns2.get('name'), 'tom2', "ns2 value correct");
ns1.set('name', 'bob');
ns2.set('name', 'alice');
ee.on('data', function () {
t.equal(ns1.get('name'), 'bob', "ns1 value bound onto emitter");
t.equal(ns2.get('name'), 'alice', "ns2 value bound onto emitter");
});
});
});
});
});

@@ -19,3 +19,3 @@ 'use strict';

t.notOk(namespace.get('inner'), "inner context should have been exited by throw");
t.equal(namespace._stack.length, 0, "should be back to global state");
t.equal(namespace._set.length, 0, "should be back to global state");

@@ -22,0 +22,0 @@ t.end();

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc